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 the TEMPLATE_DIRECTORY/compat (if exists),
219 # or from $2 (the system path), or warn about the missing file.
221 # * On unstable, we Recommend the Debian packages containing
222 # these files. The user can override them by putting his
223 # "better" version into TEMPLATE_DIRECTORY/compat.
224 # * On stable, the Debian packages are probably not available,
225 # or outdated, so we look in TEMPLATE_DIRECTORY/compat first, where
226 # our grml-live-compat package installs current file versions.
228 if [ ! -d "${BUILD_OUTPUT}/boot/$3/" ]; then
229 mkdir -p "${BUILD_OUTPUT}/boot/$3"
231 if [ -e "${TEMPLATE_DIRECTORY}/compat/$3/$1" ]; then
232 cp "${TEMPLATE_DIRECTORY}/compat/$3/$1" "${BUILD_OUTPUT}/boot/$3/"
235 if [ -e "$2/$1" ]; then
236 log "Copying $1 from system"
237 cp "$2/$1" "${BUILD_OUTPUT}/boot/$3/"
241 msg="Missing addon file: \"$1\""
242 ewarn "$msg" ; eend 1
243 log "copy_addon_file: $msg"
247 # read local (non-packaged) configuration {{{
248 LOCAL_CONFIG=/etc/grml/grml-live.local
249 if [ -r "$LOCAL_CONFIG" ] ; then
250 log "Sourcing $LOCAL_CONFIG"
253 log "No $LOCAL_CONFIG found, not sourcing it"
258 # command line parsing {{{
259 while getopts "a:C:c:d:D:g:i:I:o:r:s:t:v:bBFnNquVz" opt; do
264 c) CLASSES="$OPTARG" ;;
265 C) CONFIG="$OPTARG" ;;
267 D) GRML_FAI_CONFIG="$OPTARG" ;;
268 g) GRML_NAME="$OPTARG" ;;
269 i) ISO_NAME="$OPTARG" ;;
270 I) CHROOT_INSTALL="$OPTARG" ;;
272 N) BOOTSTRAP_ONLY=1; SKIP_MKISOFS=1; SKIP_MKSQUASHFS=1 ;;
273 o) OUTPUT="$OPTARG" ;;
274 q) SKIP_MKSQUASHFS=1 ;;
275 r) RELEASENAME="$OPTARG" ;;
276 s) SUITE="$OPTARG" ;;
277 t) TEMPLATE_DIRECTORY="$OPTARG";;
278 v) VERSION="$OPTARG" ;;
282 z) SQUASHFS_ZLIB=1 ;;
283 ?) echo "invalid option -$OPTARG" >&2; bailout 1 ;;
286 shift $(($OPTIND - 1)) # set ARGV to the first not parsed commandline parameter
289 # assume sane defaults (if not set already) {{{
290 [ -n "$ARCH" ] || ARCH="$(dpkg --print-architecture)"
291 [ -n "$BOOT_METHOD" ] || BOOT_METHOD='isolinux'
292 [ -n "$CLASSES" ] || CLASSES="GRMLBASE,GRML_MEDIUM,I386"
293 [ -n "$DATE" ] || DATE="$(date +%Y-%m-%d)"
294 [ -n "$DISTRI_INFO" ] || DISTRI_INFO='Grml - Live Linux for system administrators '
295 [ -n "$DISTRI_NAME" ] || DISTRI_NAME="grml"
296 [ -n "$DISTRI_SPLASH" ] || DISTRI_SPLASH='grml.png'
297 [ -n "$FORCE_ISO_REBUILD" ] || FORCE_ISO_REBUILD="false"
298 [ -n "$GRML_FAI_CONFIG" ] || GRML_FAI_CONFIG='/etc/grml/fai'
299 [ -n "$GRML_NAME" ] || GRML_NAME='grml'
300 [ -n "$HOSTNAME" ] || HOSTNAME='grml'
301 [ -n "$HYBRID_METHOD" ] || HYBRID_METHOD='manifold'
302 [ -n "$NFSROOT_CONF" ] || NFSROOT_CONF="${GRML_FAI_CONFIG}/make-fai-nfsroot.conf"
303 [ -n "$RELEASENAME" ] || RELEASENAME='grml-live rocks'
304 [ -n "$SOURCES_LIST_OUTPUT" ] || SOURCES_LIST_OUTPUT="${GRML_FAI_CONFIG}/config/files/etc/apt/sources.list/GRML_LIVE_SOURCES_LIST"
305 [ -n "$SQUASHFS_EXCLUDES_FILE" ] || SQUASHFS_EXCLUDES_FILE="${GRML_FAI_CONFIG}/config/grml/squashfs-excludes"
306 [ -n "$SUITE" ] || SUITE='squeeze'
307 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
308 [ -n "$USERNAME" ] || USERNAME='grml'
309 [ -n "$VERSION" ] || VERSION='0.0.1'
311 # output specific stuff, depends on $OUTPUT (iff not set):
312 [ -n "$OUTPUT" ] || OUTPUT='/grml/grml-live'
313 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
314 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
315 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
318 # some misc checks before executing FAI {{{
319 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
320 specify it on the command line using the -c option."
321 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
322 specify it on the command line using the -o option."
324 # trim characters that are known to cause problems inside $GRML_NAME;
325 # for example isolinux does not like '-' inside the directory name
326 [ -n "$GRML_NAME" ] && export SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
328 # export variables to have them available in fai scripts:
329 [ -n "$GRML_NAME" ] && export GRML_NAME="$GRML_NAME"
330 [ -n "$RELEASENAME" ] && export RELEASENAME="$RELEASENAME"
333 # ZERO_LOGFILE - check for backwards compatibility reasons {{{
334 # this was default behaviour until grml-live 0.9.34:
335 if [ -n "$ZERO_LOGFILE" ] ; then
336 PRESERVE_LOGFILE='' # make sure it's cleaned then
337 ewarn "Please consider disabling the \$ZERO_LOGFILE option as grml-live clears..."
338 ewarn "... the logfile $LOGFILE by default (unless \$PRESERVE_LOGFILE is set) nowadays."
343 # ask user whether the setup is ok {{{
344 if [ -z "$FORCE" ] ; then
346 echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
348 echo " FAI classes: $CLASSES"
349 [ -r "$LOCAL_CONFIG" ] && echo " Local config: /etc/grml/grml-live.local"
350 [ -n "$CONFIG" ] && echo " Configuration: $CONFIG"
351 [ -n "$GRML_FAI_CONFIG" ] && echo " Config directory: $GRML_FAI_CONFIG"
352 echo " main directory: $OUTPUT"
353 [ -n "$CHROOT_OUTPUT" ] && echo " Chroot target: $CHROOT_OUTPUT"
354 [ -n "$BUILD_OUTPUT" ] && echo " Build target: $BUILD_OUTPUT"
355 [ -n "$ISO_OUTPUT" ] && echo " ISO target: $ISO_OUTPUT"
356 [ -n "$GRML_NAME" ] && echo " Grml name: $GRML_NAME"
357 [ -n "$RELEASENAME" ] && echo " Release name: $RELEASENAME"
358 [ -n "$DATE" ] && echo " Build date: $DATE"
359 [ -n "$VERSION" ] && echo " Grml version: $VERSION"
360 [ -n "$SUITE" ] && echo " Debian suite: $SUITE"
361 [ -n "$ARCH" ] && echo " Architecture: $ARCH"
362 [ -n "$BOOT_METHOD" ] && echo " Boot method: $BOOT_METHOD"
363 [ -n "$HYBRID_METHOD" ] && echo " Hybrid method: $HYBRID_METHOD"
364 [ -n "$TEMPLATE_DIRECTORY" ] && echo " Template files: $TEMPLATE_DIRECTORY"
365 [ -n "$CHROOT_INSTALL" ] && echo " Install files from directory to chroot: $CHROOT_INSTALL"
366 [ -n "$BOOTID" ] && echo " Boot identifier: $BOOTID"
367 [ -n "$NO_BOOTID" ] && echo " Skipping bootid feature."
368 [ -n "$DEFAULT_BOOTOPTIONS" ] && echo " Adding default bootoptions: \"$DEFAULT_BOOTOPTIONS\""
369 [ -n "$FAI_ARGS" ] && echo " Additional arguments for FAI: $FAI_ARGS"
370 [ -n "$LOGFILE" ] && echo " Logging to file: $LOGFILE"
371 [ -n "$SQUASHFS_ZLIB" ] && echo " Using ZLIB (instead of LZMA/XZ) compression."
372 [ -n "$SQUASHFS_OPTIONS" ] && echo " Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
373 [ -n "$VERBOSE" ] && echo " Using VERBOSE mode."
374 [ -n "$UPDATE" ] && echo " Executing UPDATE instead of fresh installation."
375 if [ -n "$BOOTSTRAP_ONLY" ] ; then
376 echo " Bootstrapping only and not building (files for) ISO."
378 [ -n "$SKIP_MKSQUASHFS" ] && echo " Skipping creation of SQUASHFS file."
379 [ -n "$SKIP_MKISOFS" ] && echo " Skipping creation of ISO file."
380 [ -n "$BUILD_ONLY" ] && echo " Executing BUILD_ONLY instead of fresh installation or UPDATE."
381 [ -n "$BUILD_DIRTY" ] && echo " Executing BUILD_DIRTY to leave chroot untouched."
384 echo -n "Is this ok for you? [y/N] "
386 if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
387 bailout 1 "Exiting as requested."
393 # clean/zero/remove logfiles {{{
395 if [ -n "$PRESERVE_LOGFILE" ] ; then
396 echo "Preserving logfile $LOGFILE as requested via \$PRESERVE_LOGFILE"
398 # make sure it is empty (as it is e.g. appended to grml-live-db)
402 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
403 if [ -d /var/log/fai/"$HOSTNAME" ] ; then
404 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
405 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
406 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
407 rm -f /var/log/fai/"$HOSTNAME"/last \
408 /var/log/fai/"$HOSTNAME"/last-dirinstall \
409 /var/log/fai/"$HOSTNAME"/last-softupdate
414 # source config and startup {{{
415 if [ -n "$CONFIG" ] ; then
416 if ! [ -f "$CONFIG" ] ; then
417 log "Error: $CONFIG could not be read. Exiting. [$(date)]"
418 eerror "Error: $CONFIG could not be read. Exiting." ; eend 1
421 log "Sourcing $CONFIG"
426 start_seconds=$(cut -d . -f 1 /proc/uptime)
427 log "------------------------------------------------------------------------------"
428 log "Starting grml-live [${GRML_LIVE_VERSION}] run on $(date)"
429 log "Executed grml-live command line:"
432 einfo "Logging actions to logfile $LOGFILE"
435 # on-the-fly configuration {{{
436 mkdir -p "$(dirname $SOURCES_LIST_OUTPUT)" # might not be present in -D config space
438 cat > "$SOURCES_LIST_OUTPUT" << EOF
439 # NOTE: This file is *NOT* meant for manual customisation! This file is
440 # installed temporarily only by grml-live and will be overriden in the
441 # installation and configuration process then.
444 if [ -n "$MIRROR_DIRECTORY" ] ; then
445 if ! [ -d "$MIRROR_DIRECTORY/debian" ] ; then
446 log "Error: $MIRROR_DIRECTORY/debian does not seem to exist. Exiting. [$(date)]"
447 eerror "Error: $MIRROR_DIRECTORY/debian does not seem to exist. Exiting." ; eend 1
450 echo "$MIRROR_SOURCES" >> "$SOURCES_LIST_OUTPUT"
453 if [ -n "$FAI_DEBOOTSTRAP" ] ; then
454 sed "s#^FAI_DEBOOTSTRAP=.*#FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"#" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
457 # does this suck? YES!
458 # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
460 unstable) SUITE='sid' ;;
461 # make sure that we *NEVER* write any broken suite name to sources.list,
462 # otherwise we won't be able to adjust it one next (correct) execution
470 *) echo "Sorry, $SUITE is not a valid Debian suite, exiting.">&2; bailout 1 ;;
472 export SUITE # make sure it's available in FAI scripts
474 if [ -n "${GRML_LIVE_SOURCES:-}" ] ; then
475 DIST=" etch\| stable\| lenny\| squeeze\| wheezy\| testing\| sid\| unstable"
476 echo "# generated based on \$GRML_LIVE_SOURCES by grml-live
477 $GRML_LIVE_SOURCES" | \
478 sed -e "s/\(^deb .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/;
479 s/\(^deb-src .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/" >> "$SOURCES_LIST_OUTPUT"
481 cat >> "$SOURCES_LIST_OUTPUT" << EOF
482 # generated by grml-live
483 deb http://deb.grml.org/ grml-stable main
484 deb http://deb.grml.org/ grml-testing main
485 deb http://cdn.debian.net/debian $SUITE main contrib non-free
489 # notice: activate grml-live pool when building against unstable or testing:
490 if grep -qwe unstable -qwe sid -qwe testing -qwe wheezy "$SOURCES_LIST_OUTPUT" ; then
491 grep -q 'grml-live.*main' "$SOURCES_LIST_OUTPUT" || \
492 grep grml-stable "$SOURCES_LIST_OUTPUT" | \
493 sed 's/grml-stable/grml-live/' >> "$SOURCES_LIST_OUTPUT"
495 grep -q 'grml-live.*main' "$SOURCES_LIST_OUTPUT" && \
496 sed -i 's/.*grml-live.*main/# removed grml-live repository/' "$SOURCES_LIST_OUTPUT"
499 for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" "$NFSROOT_CONF" ; do
500 if [ -n "$file" ] ; then
501 sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
505 # validate whether the specified architecture class matches the
506 # architecture (option), otherwise installation of kernel will fail
507 if echo $CLASSES | grep -qi i386 ; then
508 if ! [[ "$ARCH" == "i386" ]] ; then
509 log "Error: You specified the I386 class but are trying to build something else (AMD64?)."
510 eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
511 eerror "Tip: Either invoke grml-live with '-a i386' or adjust the architecture class. Exiting."
515 elif echo $CLASSES | grep -qi amd64 ; then
516 if ! [[ "$ARCH" == "amd64" ]] ; then
517 log "Error: You specified the AMD64 class but are trying to build something else (I386?)."
518 eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
519 eerror "Tip: Either invoke grml-live with '-a amd64' or adjust the architecture class. Exiting."
525 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
526 sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
528 sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
532 # CHROOT_OUTPUT - execute FAI {{{
533 if [ -n "$BUILD_DIRTY" ]; then
534 log "Skipping stage 'fai' as requested via option -B"
535 ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
537 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
539 # provide inform fai about the ISO we build
540 [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
541 echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
542 [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
543 [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
545 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
546 FAI_ACTION=softupdate
548 FAI_ACTION=dirinstall
551 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
552 if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
553 log "Error: does not look like you have a working chroot. Updating/building not possible."
554 eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
560 if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
561 log "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
562 ewarn "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
564 mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
566 if [ -n "${MIRROR_DIRECTORY}" ] ; then
567 mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
568 mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
571 # tell dpkg to use "unsafe io" during the build
572 [ -d "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d" ] || mkdir -p "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d"
573 echo force-unsafe-io > "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
575 log "Executed FAI command line:"
576 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"
577 BUILD_ONLY="$BUILD_ONLY" BOOTSTRAP_ONLY="$BOOTSTRAP_ONLY" fai $VERBOSE \
578 -C "$GRML_FAI_CONFIG" -s "file:///$GRML_FAI_CONFIG/config" -c"$CLASSES" \
579 -u "$HOSTNAME" "$FAI_ACTION" "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
580 RC="$PIPESTATUS" # notice: bash-only
582 rm -f "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
584 FORCE_ISO_REBUILD=true
586 if [ "$RC" != 0 ] ; then
587 log "Error: critical error while executing fai [exit code ${RC}]. Exiting."
588 eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
591 einfo "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
592 log "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
593 echo "$GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]" > $CHROOT_OUTPUT/etc/grml_version
594 chmod 644 $CHROOT_OUTPUT/etc/grml_version
595 einfo "Rebuilding initramfs"
596 # make sure new /etc/grml_version reaches initramfs, iterate over all
597 # present kernel versions (note: we can't really handle more than one
598 # kernel version anyway right now)
599 # chroot $CHROOT_OUTPUT update-initramfs -u -t => might break when using kernel-package :(
600 for initrd in "$(basename $CHROOT_OUTPUT/boot/vmlinuz-*)" ; do
601 if ! chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -c ; then
602 einfo "Creating fresh initrd did not work, trying update instead:"
603 log "Creating fresh initrd did not work, trying update instead:"
604 chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -u
610 # Remove all FAI logs from chroot if class RELEASE is used:
611 if [ -f "$CHROOT_OUTPUT"/etc/grml_fai_release ] ; then
612 rm -rf "$CHROOT_OUTPUT"/var/log/fai/*
613 rm -f "$CHROOT_OUTPUT"/var/log/install_packages.list
618 # notice: 'fai dirinstall' does not seem to exit appropriate, so:
620 CHECKLOG=/var/log/fai/$HOSTNAME/last
621 if [ -r "$CHECKLOG/software.log" ] ; then
622 # 1 errors during executing of commands
623 grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
624 grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
625 grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
626 grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
627 grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
630 if [ -r "$CHECKLOG/shell.log" ] ; then
631 grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=6
634 if [ -n "$ERROR" ] ; then
635 log "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
636 eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
637 eerror "Note: check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
641 log "Finished execution of stage 'fai dirinstall' [$(date)]"
642 einfo "Finished execution of stage 'fai dirinstall'"
645 einfo "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
646 log "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
652 # package validator {{{
653 CHECKLOG=/var/log/fai/$HOSTNAME/last
655 if [ -r "$CHECKLOG/package_errors.log" ] && grep -q '[a-z]' "$CHECKLOG/package_errors.log" ; then
657 if [ -n "$EXIT_ON_MISSING_PACKAGES" -a -z "$BUILD_DIRTY" ] ; then
658 eerror "The following packages were requested for installation but could not be processed:"
659 cat $CHECKLOG/package_errors.log
660 eerror "... exiting as requested via \$EXIT_ON_MISSING_PACKAGES."
664 ewarn "The following packages were requested for installation but could not be processed:"
665 cat $CHECKLOG/package_errors.log
671 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
672 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
673 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
676 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
677 if [ -n "$BOOTSTRAP_ONLY" ] ; then
678 log "Skipping stage 'boot' as building with bootstrap only."
679 ewarn "Skipping stage 'boot' as building with bootstrap only." ; eend 0
681 if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
682 log "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already."
683 ewarn "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already." ; eend 0
686 [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
687 [ -d "$BUILD_OUTPUT"/boot/"${SHORT_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
689 # if we don't have an initrd we a) can't boot and b) there was an error
690 # during build, so check for the file:
691 INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
692 if [ -n "$INITRD" ] ; then
693 cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.gz
694 find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
696 log "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
697 eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
701 KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
702 if [ -n "$KERNEL_IMAGE" ] ; then
703 cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/linux26
705 log "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
706 eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
710 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
711 if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
712 log "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
713 eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
717 # copy _required_ isolinux files
718 for file in ifcpu64.c32 isolinux.bin vesamenu.c32; do
719 copy_addon_file "${file}" /usr/lib/syslinux isolinux
722 # *always* copy files to output directory so the variables
723 # get adjusted according to the build.
724 cp ${TEMPLATE_DIRECTORY}/boot/isolinux/* "$BUILD_OUTPUT"/boot/isolinux/
726 if [ -n "$NO_ADDONS" ] ; then
727 log "Skipping installation of boot addons as requested via \$NO_ADDONS."
728 einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
730 if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
731 log "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
732 ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
734 # copy addons from system packages or grml-live-compat
735 copy_addon_file ipxe.lkrn /usr/lib/ipxe addons
736 copy_addon_file pci.ids /usr/share/misc addons
737 copy_addon_file memtest86+.bin /boot addons
738 for file in memdisk chain.c32 hdt.c32 menu.c32; do
739 copy_addon_file "${file}" /usr/lib/syslinux addons
742 # make memtest filename FAT16/8.3 compatible
743 mv "${BUILD_OUTPUT}/boot/addons/memtest86+.bin" \
744 "${BUILD_OUTPUT}/boot/addons/memtest"
746 # copy only files so we can handle bsd4grml on its own
747 for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
748 test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
751 if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
752 log "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
753 einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
755 if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
756 cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
758 log "Missing addon file: bsd4grml"
759 ewarn "Missing addon file: bsd4grml" ; eend 0
763 fi # no "$TEMPLATE_DIRECTORY"/boot/addons
766 if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
767 mkdir -p "${BUILD_OUTPUT}/boot/grub"
769 cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
771 if [ -e ${TEMPLATE_DIRECTORY}/compat/grub/linux.mod ]; then
772 cp "${TEMPLATE_DIRECTORY}"/compat/grub/* "${BUILD_OUTPUT}"/boot/grub/
774 if ! which "grub-mkimage" >/dev/null 2>&1 ; then
775 log "grub-mkimage not found, skipping Grub step therefore." ; eend 0
776 ewarn "grub-mkimage not found, skipping Grub step therefore."
777 ewarn "Please install grub-pc-bin or grub-common >= 1.98+20100804-14." ; eend 0
778 elif ! grub-mkimage --help | grep -q -- --format ; then
779 log "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore." ; eend 0
780 ewarn "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore."
781 ewarn "Please install grub-common >= 1.98+20100804-14 or grub-pc-bin." ; eend 0
783 # copy system grub files if grml-live-compat is not installed
784 cp -a /usr/lib/grub/*-pc/*.mod "${BUILD_OUTPUT}"/boot/grub/
785 cp -a /usr/lib/grub/*-pc/*.o "${BUILD_OUTPUT}"/boot/grub/
786 cp -a /usr/lib/grub/*-pc/*.lst "${BUILD_OUTPUT}"/boot/grub/
787 cp -a /usr/share/grub/ascii.pf2 "${BUILD_OUTPUT}"/boot/grub/
788 grub-mkimage -d /usr/lib/grub/*-pc -o \
789 "${BUILD_OUTPUT}/boot/grub/core.img" biosdisk iso9660 --format=i386-pc
793 if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
794 log "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
795 eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
799 [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
800 cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
802 # adjust boot splash information:
803 RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
804 RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
805 RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
807 if [ -r "$BUILD_OUTPUT"/GRML/grml-version ] ; then
808 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
809 sed -i "s/%DATE%/$DATE/" "$BUILD_OUTPUT"/GRML/grml-version
812 # make sure the squashfs filename is set accordingly:
813 SQUASHFS_NAME="$GRML_NAME.squashfs"
815 if [ -n "$NO_BOOTID" ] ; then
816 log 'Skipping bootid feature as requested via $NO_BOOTID.'
817 einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
819 [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
820 [ -d "$BUILD_OUTPUT"/conf ] || mkdir "$BUILD_OUTPUT"/conf
821 einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
822 log "Generating /conf/bootid.txt with entry ${BOOTID}."
823 echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
827 # adjust all variables in the templates with the according distribution information
828 for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
829 "${BUILD_OUTPUT}"/boot/grub/* ; do
830 if [ -r "${file}" ] ; then
831 sed -i "s/%ARCH%/$ARCH/g" "${file}"
832 sed -i "s/%DATE%/$DATE/g" "${file}"
833 sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g" "${file}"
834 sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g" "${file}"
835 sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g" "${file}"
836 sed -i "s/%GRML_NAME%/$GRML_NAME/g" "${file}"
837 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g" "${file}"
838 sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g" "${file}"
839 sed -i "s/%SHORT_NAME%/$SHORT_NAME/g" "${file}"
840 sed -i "s/%VERSION%/$VERSION/g" "${file}"
842 [ -n "$DEFAULT_BOOTOPTIONS" ] && sed -i "s/ boot=live/ boot=live $DEFAULT_BOOTOPTIONS/" "${file}"
844 if [ -n "$NO_BOOTID" ] ; then
845 sed -i "s/ bootid=%BOOTID%//g" "${file}" # drop bootid bootoption
847 sed -i "s/%BOOTID%/$BOOTID/g" "${file}" # adjust bootid=... argument
852 # adjust bootsplash accordingly but make sure the string has the according lenght
853 SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
854 SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
855 for file in f4 f5 ; do
856 if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
857 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
858 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
862 # generate addon list
863 rm -f "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
864 for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
865 include_name=$(basename "$name")
866 echo "include $include_name" >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
869 if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
870 log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
871 echo "include grmlmain.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
872 echo "include default.cfg" > "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
873 echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
874 echo "include grml.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
876 for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
877 echo "include $(basename $f)" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
880 echo "include options.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
881 if [ ! -n "$NO_ADDONS" ] ; then
882 echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
884 echo "include isoprompt.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
885 echo "include hd.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
886 echo "include hidden.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
887 else # assume we are building a custom distribution:
888 log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
889 einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
890 if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
891 log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
893 einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
897 log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
898 echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
899 [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
903 # use old style console based isolinux method only if requested:
904 if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
905 log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
906 einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
907 if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
908 einfo "include for console.cfg already found, nothing to do."
911 log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
912 einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
913 echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
917 log 'Using graphical boot menu.'
918 if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
919 log "include for vesamenu.cfg already found, nothing to do."
921 log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
922 echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
926 if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
927 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
930 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
931 if ! [ -r "$DPKG_LIST" ] ; then
932 ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
934 einfo "Storing package list information as /GRML/${GRML_NAME}-packages.txt on ISO."
935 cp "$DPKG_LIST" "${BUILD_OUTPUT}/GRML/${GRML_NAME}-packages.txt"
939 # autostart for Windows:
940 if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
941 cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
944 FORCE_ISO_REBUILD=true
945 einfo "Finished execution of stage 'boot'" ; eend 0
949 log 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
950 eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
954 # support installation of local files into the chroot/ISO
955 if [ -n "$CHROOT_INSTALL" ] ; then
956 if ! [ -d "$CHROOT_INSTALL" ] ; then
957 log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
958 ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
960 log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
961 einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
962 rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
964 einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
965 FORCE_ISO_REBUILD=true
969 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
970 log "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
971 ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
972 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
973 log "Skipping stage 'squashfs' as requested via option -q or -N"
974 ewarn "Skipping stage 'squashfs' as requested via option -q or -N" ; eend 0
976 [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
977 # make sure we don't leave (even an empty) base.tgz:
978 [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
980 # if unconfigured default to squashfs-tools' mksquashfs binary
981 if [ -z "$SQUASHFS_BINARY" ] ; then
982 SQUASHFS_BINARY='mksquashfs'
985 if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
986 log "Using mksquashfs binary ${SQUASHFS_BINARY}"
987 einfo "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
989 log "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
990 eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
994 # use sane defaults if $SQUASHFS_OPTIONS isn't set
995 if [ -z "$SQUASHFS_OPTIONS" ] ; then
996 # use blocksize 256k as this gives best result with regards to time + compression
997 SQUASHFS_OPTIONS="-b 256k"
999 # set lzma/xz compression by default, unless -z option has been specified on command line
1000 if [ -z "$SQUASHFS_ZLIB" ] ; then
1001 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp xz"
1003 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp gzip"
1007 # support exclusion of files via exclude-file:
1008 if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
1009 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE -wildcards"
1012 # get rid of unnecessary files when building grml-small for final release:
1013 if echo "$CLASSES" | grep -q GRML_SMALL ; then
1014 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
1018 SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
1020 # informational stuff
1021 [ -n "$SQUASHFS_OPTIONS" ] && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
1022 [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
1023 einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
1025 log "$SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS"
1027 if $SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
1028 -noappend $SQUASHFS_OPTIONS 2>"${SQUASHFS_STDERR}" ; then
1029 echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
1030 log "Finished execution of stage 'squashfs' [$(date)]"
1031 einfo "Finished execution of stage 'squashfs'" ; eend 0
1033 log "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1034 log "$(cat $SQUASHFS_STDERR)"
1035 eerror "Error: there was a critical error executing stage 'squashfs':"
1036 cat "${SQUASHFS_STDERR}"
1041 FORCE_ISO_REBUILD=true
1044 # create md5sum file:
1045 if [ -z "$BOOTSTRAP_ONLY" ] ; then
1046 ( cd $BUILD_OUTPUT/GRML &&
1047 find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1051 # ISO_OUTPUT - mkisofs {{{
1052 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1053 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1055 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1056 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1057 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1058 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1061 # Just until http://bts.grml.org/grml/issue945 has been resolved.
1062 # HYBRID_METHOD defaults to manifold, so make sure the default works OOTB.
1063 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1064 log "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1065 ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1066 HYBRID_METHOD='grub2'
1070 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ] ; then
1071 log "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1072 ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1073 elif [ -n "$SKIP_MKISOFS" ] ; then
1074 log "Skipping stage 'iso build' as requested via option -n or -N"
1075 ewarn "Skipping stage 'iso build' as requested via option -n or -N" ; eend 0
1077 mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1079 if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1080 log "Forcing rebuild of ISO because files on ISO have been modified."
1081 einfo "Forcing rebuild of ISO because files on ISO have been modified."
1084 # support mkisofs as well as genisoimage
1085 if which mkisofs >/dev/null 2>&1; then
1087 elif which genisoimage >/dev/null 2>&1; then
1088 MKISOFS='genisoimage'
1090 log "Error: neither mkisofs nor genisoimage available - can not create ISO."
1091 eerror "Error: neither mkisofs nor genisoimage available - can not create ISO." ; eend 1
1096 if cd "$BUILD_OUTPUT" ; then
1097 if [ "$BOOT_METHOD" = "grub2" ]; then
1098 # make a 2048-byte bootsector for El Torito
1099 dd if=/dev/zero of=boot/grub/toriboot.bin bs=512 count=4 2>/dev/null
1100 # those are in 2048-byte sectors, so 1 16 matches 4 63 below
1101 echo 1 16 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -B 11 | \
1102 dd of=boot/grub/toriboot.bin conv=notrunc 2>/dev/null
1104 log "$MKISOFS -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J $BOOT_ARGS -o ${ISO_OUTPUT}/${ISO_NAME} ."
1105 "$MKISOFS" -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1106 -l -r -J $BOOT_ARGS -no-pad \
1107 -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1108 # both of these need core.img there, so it’s easier to write it here
1109 if [ "$BOOT_METHOD" = "grub2" ] || [ "$HYBRID_METHOD" = "grub2" ]; then
1110 # must be <= 30720 bytes
1111 dd if=boot/grub/core.img of="${ISO_OUTPUT}/${ISO_NAME}" \
1112 conv=notrunc bs=512 seek=4 2>/dev/null
1115 # pad the output ISO to multiples of 256 KiB for partition table support
1116 siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1117 cyls=$((siz / 512 / 32 / 16 + 1)) # C=$cyls H=16 S=32
1118 siz=$((cyls * 16 * 32 * 512)) # size after padding
1119 dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1120 of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1122 # support disabling hybrid ISO image
1123 if [ "$HYBRID_METHOD" = "disable" ] ; then\
1124 log "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1125 einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1127 # use isohybrid only on request
1128 elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
1129 if ! which isohybrid >/dev/null 2>&1 ; then
1130 bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1132 log "Creating hybrid ISO file with isohybrid method"
1133 einfo "Creating hybrid ISO file with isohybrid method"
1134 # Notes for consideration:
1135 # "-entry 4 -type 1c"
1136 # * using 4 as the partition number is supposed to help with BIOSes
1137 # that only support USB-Zip boot
1138 # * using 1c (i.e. hidden FAT32 LBA), instead of the default 0x17
1139 # (hidden NTFS, IIRC), as the partition type is sometimes needed
1140 # to get the BIOS even look at the partition created by isohybrid
1141 isohybrid "${ISO_OUTPUT}/${ISO_NAME}"
1144 # by default use our manifold boot method:
1146 # isoinfo is part of both mkisofs and genisoimage so we're good
1147 bootoff=$(isoinfo -l -i "${ISO_OUTPUT}/${ISO_NAME}" | \
1148 sed -n '/^.*\[ *\([0-9]*\)[] ].* ISOLINUX.BIN;1 *$/s//\1/p')
1149 if ! [ -r boot/grub/core.img ] ; then
1150 ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1151 elif [ "${bootoff:-0}" -lt 1 ] ; then
1152 ewarn "isolinux.bin not found on the ISO file, disabling manifold boot"
1154 log "Creating hybrid ISO file with manifold method"
1155 einfo "Creating hybrid ISO file with manifold method"
1156 if [ "$HYBRID_METHOD" = "grub2" ] ; then
1157 # 512 bytes: MBR, partition table, load GRUB 2
1158 echo 4 63 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 4:0x96 -g $cyls:16:32
1160 # read only one but 2048-byte sized (scale: << 2) sector
1161 echo $bootoff $bootoff | \
1162 mksh /usr/share/grml-live/scripts/bootilnx.mksh -A -M 4:0x96 -g $cyls:16:32 -S 2
1163 fi | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1168 # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1169 case $CLASSES in *RELEASE*)
1172 if cd $ISO_OUTPUT ; then
1173 md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1174 touch -r ${ISO_NAME} ${ISO_NAME}.md5
1175 sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1176 touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1185 if [ "$RC" = 0 ] ; then
1186 log "Finished execution of stage 'iso build' [$(date)]"
1187 einfo "Finished execution of stage 'iso build'" ; eend 0
1189 log "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1190 eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1196 # log build information to database if grml-live-db is installed and enabled {{{
1198 if [ -d /usr/share/grml-live-db ] ; then
1201 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1202 [ -n "$DPKG_DATABASE" ] || DPKG_DATABASE=/var/log/grml-live.db
1203 [ -n "$DPKG_DBSCRIPT" ] || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1204 [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1206 if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1207 log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1208 eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1212 # disable by default for now, not sure whether really everyone is using a local db file
1213 #if ! touch "$DPKG_DATABASE" ; then
1214 # eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1218 if ! [ -r "$DPKG_LIST" ] ; then
1219 log "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1220 ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1222 einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1223 log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1224 log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1227 if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1243 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1244 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1246 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1248 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1252 ## END OF FILE #################################################################
1253 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2