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
163 # some important functions {{{
166 # usage: log "string to log"
167 log() { echo "$*" >> $LOGFILE ; }
169 # cut string at character number int = $1
170 # usage: cut_string 5 "1234567890" will output "12345"
172 [ -n "$2" ] || return 1
173 echo "$2" | head -c "$1"; echo -ne "\n"
176 # prepend int = $1 spaces before string = $2
177 # usage: extend_string_begin 5 "123" will output " 123"
178 extend_string_begin() {
179 [ -n "$2" ] || return 1
180 local COUNT="$(echo $2 | wc -c)"
181 local FILL="$(expr $COUNT - $1)"
182 while [ "$FILL" -gt 1 ] ; do
184 local FILL=$(expr $FILL - 1)
186 while [ "$FILL" -lt 1 ] ; do
188 local FILL=$(expr $FILL + 1)
190 echo "$2" | head -c "$1"; echo -ne "\n"
193 # append int = $1 spaces to string = $2
194 # usage: extend_string_begin 5 "123" will output "123 "
195 extend_string_end() {
196 [ -n "$2" ] || return 1
197 echo -n "$2" | head -c "$1"
198 local COUNT="$(echo $2 | wc -c)"
199 local FILL="$(expr $COUNT - $1)"
200 while [ "$FILL" -gt 1 ] ; do
202 local FILL=$(expr $FILL - 1)
204 while [ "$FILL" -lt 1 ] ; do
206 local FILL=$(expr $FILL + 1)
211 # Copy addonfile $1 from either
212 # * the chroot (via $2, the system path),
213 # * or from TEMPLATE_DIRECTORY/compat (if exists),
214 # * or from the host system (again, using $2),
215 # or warn about the missing file.
218 # * We assume that the chroot always has a "good" version of
219 # the file. Also it makes sources handling easier.
220 # * On unstable, we Recommend the Debian packages containing
221 # these files. The user can override them by putting his
222 # "better" version into the chroot.
223 # * On stable, the Debian packages are probably not available,
224 # or outdated, so we look in TEMPLATE_DIRECTORY/compat first, where
225 # our grml-live-compat package installs current file versions.
227 DEST="${BUILD_OUTPUT}/boot/$3"
228 if [ ! -d "${DEST}/" ]; then
231 if [ -e "$CHROOT_OUTPUT/$2/$1" ]; then
232 log "Copying $1 from chroot"
233 cp "$CHROOT_OUTPUT/$2/$1" "${DEST}/"
236 if [ -e "${TEMPLATE_DIRECTORY}/compat/$3/$1" ]; then
237 log "Copying $1 from grml-live-compat"
238 cp "${TEMPLATE_DIRECTORY}/compat/$3/$1" "${DEST}/"
241 if [ -e "$2/$1" ]; then
242 log "Copying $1 from system"
243 cp "$2/$1" "${DEST}/"
247 msg="Missing addon file: \"$1\""
248 ewarn "$msg" ; eend 1
249 log "copy_addon_file: $msg"
253 # read local (non-packaged) configuration {{{
254 LOCAL_CONFIG=/etc/grml/grml-live.local
255 if [ -r "$LOCAL_CONFIG" ] ; then
262 # command line parsing {{{
263 while getopts "a:C:c:d:D:g:i:I:o:r:s:t:v:bBFnNquVz" opt; do
268 c) CLASSES="$OPTARG" ;;
269 C) CONFIG="$OPTARG" ;;
271 D) GRML_FAI_CONFIG="$OPTARG" ;;
272 g) GRML_NAME="$OPTARG" ;;
273 i) ISO_NAME="$OPTARG" ;;
274 I) CHROOT_INSTALL="$OPTARG" ;;
276 N) BOOTSTRAP_ONLY=1; SKIP_MKISOFS=1; SKIP_MKSQUASHFS=1 ;;
277 o) OUTPUT="$OPTARG" ;;
278 q) SKIP_MKSQUASHFS=1 ;;
279 r) RELEASENAME="$OPTARG" ;;
280 s) SUITE="$OPTARG" ;;
281 t) TEMPLATE_DIRECTORY="$OPTARG";;
282 v) VERSION="$OPTARG" ;;
286 z) SQUASHFS_ZLIB=1 ;;
287 ?) echo "invalid option -$OPTARG" >&2; bailout 1 ;;
290 shift $(($OPTIND - 1)) # set ARGV to the first not parsed commandline parameter
293 # assume sane defaults (if not set already) {{{
294 [ -n "$ARCH" ] || ARCH="$(dpkg --print-architecture)"
295 [ -n "$BOOT_METHOD" ] || BOOT_METHOD='isolinux'
296 [ -n "$CLASSES" ] || CLASSES="GRMLBASE,GRML_MEDIUM,I386"
297 [ -n "$DATE" ] || DATE="$(date +%Y-%m-%d)"
298 [ -n "$DISTRI_INFO" ] || DISTRI_INFO='Grml - Live Linux for system administrators '
299 [ -n "$DISTRI_NAME" ] || DISTRI_NAME="grml"
300 [ -n "$DISTRI_SPLASH" ] || DISTRI_SPLASH='grml.png'
301 [ -n "$FORCE_ISO_REBUILD" ] || FORCE_ISO_REBUILD="false"
302 [ -n "$GRML_FAI_CONFIG" ] || GRML_FAI_CONFIG='/etc/grml/fai'
303 [ -n "$GRML_NAME" ] || GRML_NAME='grml'
304 [ -n "$HOSTNAME" ] || HOSTNAME='grml'
305 [ -n "$HYBRID_METHOD" ] || HYBRID_METHOD='manifold'
306 [ -n "$NFSROOT_CONF" ] || NFSROOT_CONF="${GRML_FAI_CONFIG}/make-fai-nfsroot.conf"
307 [ -n "$RELEASENAME" ] || RELEASENAME='grml-live rocks'
308 [ -n "$SOURCES_LIST_OUTPUT" ] || SOURCES_LIST_OUTPUT="${GRML_FAI_CONFIG}/config/files/etc/apt/sources.list/GRML_LIVE_SOURCES_LIST"
309 [ -n "$SQUASHFS_EXCLUDES_FILE" ] || SQUASHFS_EXCLUDES_FILE="${GRML_FAI_CONFIG}/config/grml/squashfs-excludes"
310 [ -n "$SUITE" ] || SUITE='squeeze'
311 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
312 [ -n "$USERNAME" ] || USERNAME='grml'
313 [ -n "$VERSION" ] || VERSION='0.0.1'
315 # output specific stuff, depends on $OUTPUT (iff not set):
316 [ -n "$OUTPUT" ] || OUTPUT='/grml/grml-live'
317 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
318 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
319 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
322 # some misc checks before executing FAI {{{
323 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
324 specify it on the command line using the -c option."
325 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
326 specify it on the command line using the -o option."
328 # trim characters that are known to cause problems inside $GRML_NAME;
329 # for example isolinux does not like '-' inside the directory name
330 [ -n "$GRML_NAME" ] && export SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
332 # export variables to have them available in fai scripts:
333 [ -n "$GRML_NAME" ] && export GRML_NAME="$GRML_NAME"
334 [ -n "$RELEASENAME" ] && export RELEASENAME="$RELEASENAME"
337 # ZERO_LOGFILE - check for backwards compatibility reasons {{{
338 # this was default behaviour until grml-live 0.9.34:
339 if [ -n "$ZERO_LOGFILE" ] ; then
340 PRESERVE_LOGFILE='' # make sure it's cleaned then
341 ewarn "Please consider disabling the \$ZERO_LOGFILE option as grml-live clears..."
342 ewarn "... the logfile $LOGFILE by default (unless \$PRESERVE_LOGFILE is set) nowadays."
347 # ask user whether the setup is ok {{{
348 if [ -z "$FORCE" ] ; then
350 echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
352 echo " FAI classes: $CLASSES"
353 [ -r "$LOCAL_CONFIG" ] && echo " Local config: /etc/grml/grml-live.local"
354 [ -n "$CONFIG" ] && echo " Configuration: $CONFIG"
355 [ -n "$GRML_FAI_CONFIG" ] && echo " Config directory: $GRML_FAI_CONFIG"
356 echo " main directory: $OUTPUT"
357 [ -n "$CHROOT_OUTPUT" ] && echo " Chroot target: $CHROOT_OUTPUT"
358 [ -n "$BUILD_OUTPUT" ] && echo " Build target: $BUILD_OUTPUT"
359 [ -n "$ISO_OUTPUT" ] && echo " ISO target: $ISO_OUTPUT"
360 [ -n "$GRML_NAME" ] && echo " Grml name: $GRML_NAME"
361 [ -n "$RELEASENAME" ] && echo " Release name: $RELEASENAME"
362 [ -n "$DATE" ] && echo " Build date: $DATE"
363 [ -n "$VERSION" ] && echo " Grml version: $VERSION"
364 [ -n "$SUITE" ] && echo " Debian suite: $SUITE"
365 [ -n "$ARCH" ] && echo " Architecture: $ARCH"
366 [ -n "$BOOT_METHOD" ] && echo " Boot method: $BOOT_METHOD"
367 [ -n "$HYBRID_METHOD" ] && echo " Hybrid method: $HYBRID_METHOD"
368 [ -n "$TEMPLATE_DIRECTORY" ] && echo " Template files: $TEMPLATE_DIRECTORY"
369 [ -n "$CHROOT_INSTALL" ] && echo " Install files from directory to chroot: $CHROOT_INSTALL"
370 [ -n "$BOOTID" ] && echo " Boot identifier: $BOOTID"
371 [ -n "$NO_BOOTID" ] && echo " Skipping bootid feature."
372 [ -n "$DEFAULT_BOOTOPTIONS" ] && echo " Adding default bootoptions: \"$DEFAULT_BOOTOPTIONS\""
373 [ -n "$FAI_ARGS" ] && echo " Additional arguments for FAI: $FAI_ARGS"
374 [ -n "$LOGFILE" ] && echo " Logging to file: $LOGFILE"
375 [ -n "$SQUASHFS_ZLIB" ] && echo " Using ZLIB (instead of LZMA/XZ) compression."
376 [ -n "$SQUASHFS_OPTIONS" ] && echo " Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
377 [ -n "$VERBOSE" ] && echo " Using VERBOSE mode."
378 [ -n "$UPDATE" ] && echo " Executing UPDATE instead of fresh installation."
379 if [ -n "$BOOTSTRAP_ONLY" ] ; then
380 echo " Bootstrapping only and not building (files for) ISO."
382 [ -n "$SKIP_MKSQUASHFS" ] && echo " Skipping creation of SQUASHFS file."
383 [ -n "$SKIP_MKISOFS" ] && echo " Skipping creation of ISO file."
384 [ -n "$BUILD_ONLY" ] && echo " Executing BUILD_ONLY instead of fresh installation or UPDATE."
385 [ -n "$BUILD_DIRTY" ] && echo " Executing BUILD_DIRTY to leave chroot untouched."
388 echo -n "Is this ok for you? [y/N] "
390 if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
391 bailout 1 "Exiting as requested."
397 # create log file {{{
398 [ -n "$LOGFILE" ] || LOGFILE=${OUTPUT}/grml_logs/grml-live.log
399 mkdir -p $(dirname "${LOGFILE}")
401 chown root:adm $LOGFILE
405 # clean/zero/remove logfiles {{{
407 if [ -n "$PRESERVE_LOGFILE" ] ; then
408 echo "Preserving logfile $LOGFILE as requested via \$PRESERVE_LOGFILE"
410 # make sure it is empty (as it is e.g. appended to grml-live-db)
414 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
415 if [ -d /var/log/fai/"$HOSTNAME" ] ; then
416 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
417 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
418 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
419 rm -f /var/log/fai/"$HOSTNAME"/last \
420 /var/log/fai/"$HOSTNAME"/last-dirinstall \
421 /var/log/fai/"$HOSTNAME"/last-softupdate
426 # source config and startup {{{
427 if [ -n "$CONFIG" ] ; then
428 if ! [ -f "$CONFIG" ] ; then
429 log "Error: $CONFIG could not be read. Exiting. [$(date)]"
430 eerror "Error: $CONFIG could not be read. Exiting." ; eend 1
433 log "Sourcing $CONFIG"
438 start_seconds=$(cut -d . -f 1 /proc/uptime)
439 log "------------------------------------------------------------------------------"
440 log "Starting grml-live [${GRML_LIVE_VERSION}] run on $(date)"
441 if [ -n "$LOCAL_CONFIG" ]; then
442 log "Using local config file: $LOCAL_CONFIG"
444 log "Executed grml-live command line:"
447 einfo "Logging actions to logfile $LOGFILE"
450 # on-the-fly configuration {{{
451 mkdir -p "$(dirname $SOURCES_LIST_OUTPUT)" # might not be present in -D config space
453 cat > "$SOURCES_LIST_OUTPUT" << EOF
454 # NOTE: This file is *NOT* meant for manual customisation! This file is
455 # installed temporarily only by grml-live and will be overriden in the
456 # installation and configuration process then.
459 if [ -n "$MIRROR_DIRECTORY" ] ; then
460 if ! [ -d "$MIRROR_DIRECTORY/debian" ] ; then
461 log "Error: $MIRROR_DIRECTORY/debian does not seem to exist. Exiting. [$(date)]"
462 eerror "Error: $MIRROR_DIRECTORY/debian does not seem to exist. Exiting." ; eend 1
465 echo "$MIRROR_SOURCES" >> "$SOURCES_LIST_OUTPUT"
468 if [ -n "$FAI_DEBOOTSTRAP" ] ; then
469 sed "s#^FAI_DEBOOTSTRAP=.*#FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"#" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
472 # does this suck? YES!
473 # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
475 unstable) SUITE='sid' ;;
476 # make sure that we *NEVER* write any broken suite name to sources.list,
477 # otherwise we won't be able to adjust it one next (correct) execution
485 *) echo "Sorry, $SUITE is not a valid Debian suite, exiting.">&2; bailout 1 ;;
487 export SUITE # make sure it's available in FAI scripts
489 if [ -n "${GRML_LIVE_SOURCES:-}" ] ; then
490 DIST=" etch\| stable\| lenny\| squeeze\| wheezy\| testing\| sid\| unstable"
491 echo "# generated based on \$GRML_LIVE_SOURCES by grml-live
492 $GRML_LIVE_SOURCES" | \
493 sed -e "s/\(^deb .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/;
494 s/\(^deb-src .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/" >> "$SOURCES_LIST_OUTPUT"
496 cat >> "$SOURCES_LIST_OUTPUT" << EOF
497 # generated by grml-live
498 deb http://deb.grml.org/ grml-stable main
499 deb http://deb.grml.org/ grml-testing main
500 deb http://cdn.debian.net/debian $SUITE main contrib non-free
504 # notice: activate grml-live pool when building against unstable or testing:
505 if grep -qwe unstable -qwe sid -qwe testing -qwe wheezy "$SOURCES_LIST_OUTPUT" ; then
506 grep -q 'grml-live.*main' "$SOURCES_LIST_OUTPUT" || \
507 grep grml-stable "$SOURCES_LIST_OUTPUT" | \
508 sed 's/grml-stable/grml-live/' >> "$SOURCES_LIST_OUTPUT"
510 grep -q 'grml-live.*main' "$SOURCES_LIST_OUTPUT" && \
511 sed -i 's/.*grml-live.*main/# removed grml-live repository/' "$SOURCES_LIST_OUTPUT"
514 for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" "$NFSROOT_CONF" ; do
515 if [ -n "$file" ] ; then
516 sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
520 # validate whether the specified architecture class matches the
521 # architecture (option), otherwise installation of kernel will fail
522 if echo $CLASSES | grep -qi i386 ; then
523 if ! [[ "$ARCH" == "i386" ]] ; then
524 log "Error: You specified the I386 class but are trying to build something else (AMD64?)."
525 eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
526 eerror "Tip: Either invoke grml-live with '-a i386' or adjust the architecture class. Exiting."
530 elif echo $CLASSES | grep -qi amd64 ; then
531 if ! [[ "$ARCH" == "amd64" ]] ; then
532 log "Error: You specified the AMD64 class but are trying to build something else (I386?)."
533 eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
534 eerror "Tip: Either invoke grml-live with '-a amd64' or adjust the architecture class. Exiting."
540 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
541 sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
543 sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
547 # CHROOT_OUTPUT - execute FAI {{{
548 if [ -n "$BUILD_DIRTY" ]; then
549 log "Skipping stage 'fai' as requested via option -B"
550 ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
552 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
554 # provide inform fai about the ISO we build
555 [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
556 echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
557 [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
558 [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
560 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
561 FAI_ACTION=softupdate
563 FAI_ACTION=dirinstall
566 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
567 if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
568 log "Error: does not look like you have a working chroot. Updating/building not possible."
569 eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
575 if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
576 log "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
577 ewarn "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
579 mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
581 if [ -n "${MIRROR_DIRECTORY}" ] ; then
582 mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
583 mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
586 # tell dpkg to use "unsafe io" during the build
587 [ -d "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d" ] || mkdir -p "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d"
588 echo force-unsafe-io > "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
590 log "Executed FAI command line:"
591 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"
592 BUILD_ONLY="$BUILD_ONLY" BOOTSTRAP_ONLY="$BOOTSTRAP_ONLY" fai $VERBOSE \
593 -C "$GRML_FAI_CONFIG" -s "file:///$GRML_FAI_CONFIG/config" -c"$CLASSES" \
594 -u "$HOSTNAME" "$FAI_ACTION" "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
595 RC="$PIPESTATUS" # notice: bash-only
597 rm -f "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
599 FORCE_ISO_REBUILD=true
601 if [ "$RC" != 0 ] ; then
602 log "Error: critical error while executing fai [exit code ${RC}]. Exiting."
603 eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
606 einfo "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
607 log "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
608 echo "$GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]" > $CHROOT_OUTPUT/etc/grml_version
609 chmod 644 $CHROOT_OUTPUT/etc/grml_version
610 einfo "Rebuilding initramfs"
611 # make sure new /etc/grml_version reaches initramfs, iterate over all
612 # present kernel versions (note: we can't really handle more than one
613 # kernel version anyway right now)
614 # chroot $CHROOT_OUTPUT update-initramfs -u -t => might break when using kernel-package :(
615 for initrd in "$(basename $CHROOT_OUTPUT/boot/vmlinuz-*)" ; do
616 if ! chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -c ; then
617 einfo "Creating fresh initrd did not work, trying update instead:"
618 log "Creating fresh initrd did not work, trying update instead:"
619 chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -u
625 # Remove all FAI logs from chroot if class RELEASE is used:
626 if [ -f "$CHROOT_OUTPUT"/etc/grml_fai_release ] ; then
627 rm -rf "$CHROOT_OUTPUT"/var/log/fai/*
628 rm -f "$CHROOT_OUTPUT"/var/log/install_packages.list
633 # notice: 'fai dirinstall' does not seem to exit appropriate, so:
635 CHECKLOG=/var/log/fai/$HOSTNAME/last
636 if [ -r "$CHECKLOG/software.log" ] ; then
637 # 1 errors during executing of commands
638 grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
639 grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
640 grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
641 grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
642 grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
645 if [ -r "$CHECKLOG/shell.log" ] ; then
646 grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=6
649 if [ -n "$ERROR" ] ; then
650 log "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
651 eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
652 eerror "Note: check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
656 log "Finished execution of stage 'fai dirinstall' [$(date)]"
657 einfo "Finished execution of stage 'fai dirinstall'"
660 einfo "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
661 log "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
667 # package validator {{{
668 CHECKLOG=/var/log/fai/$HOSTNAME/last
670 if [ -r "$CHECKLOG/package_errors.log" ] && grep -q '[a-z]' "$CHECKLOG/package_errors.log" ; then
672 if [ -n "$EXIT_ON_MISSING_PACKAGES" -a -z "$BUILD_DIRTY" ] ; then
673 eerror "The following packages were requested for installation but could not be processed:"
674 cat $CHECKLOG/package_errors.log
675 eerror "... exiting as requested via \$EXIT_ON_MISSING_PACKAGES."
679 ewarn "The following packages were requested for installation but could not be processed:"
680 cat $CHECKLOG/package_errors.log
686 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
687 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
688 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
691 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
692 if [ -n "$BOOTSTRAP_ONLY" ] ; then
693 log "Skipping stage 'boot' as building with bootstrap only."
694 ewarn "Skipping stage 'boot' as building with bootstrap only." ; eend 0
696 if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
697 log "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already."
698 ewarn "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already." ; eend 0
701 [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
702 [ -d "$BUILD_OUTPUT"/boot/"${SHORT_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
704 # if we don't have an initrd we a) can't boot and b) there was an error
705 # during build, so check for the file:
706 INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
707 if [ -n "$INITRD" ] ; then
708 cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.gz
709 find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
711 log "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
712 eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
716 KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
717 if [ -n "$KERNEL_IMAGE" ] ; then
718 cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/linux26
720 log "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
721 eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
725 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
726 if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
727 log "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
728 eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
732 # copy _required_ isolinux files
733 for file in ifcpu64.c32 isolinux.bin vesamenu.c32; do
734 copy_addon_file "${file}" /usr/lib/syslinux isolinux
737 # *always* copy files to output directory so the variables
738 # get adjusted according to the build.
739 cp ${TEMPLATE_DIRECTORY}/boot/isolinux/* "$BUILD_OUTPUT"/boot/isolinux/
741 if [ -n "$NO_ADDONS" ] ; then
742 log "Skipping installation of boot addons as requested via \$NO_ADDONS."
743 einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
745 if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
746 log "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
747 ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
749 # copy addons from system packages or grml-live-compat
750 copy_addon_file ipxe.lkrn /usr/lib/ipxe addons
751 copy_addon_file pci.ids /usr/share/misc addons
752 copy_addon_file memtest86+.bin /boot addons
753 for file in memdisk chain.c32 hdt.c32 menu.c32; do
754 copy_addon_file "${file}" /usr/lib/syslinux addons
757 # make memtest filename FAT16/8.3 compatible
758 mv "${BUILD_OUTPUT}/boot/addons/memtest86+.bin" \
759 "${BUILD_OUTPUT}/boot/addons/memtest"
761 # copy only files so we can handle bsd4grml on its own
762 for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
763 test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
766 if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
767 log "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
768 einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
770 if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
771 cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
773 log "Missing addon file: bsd4grml"
774 ewarn "Missing addon file: bsd4grml" ; eend 0
778 fi # no "$TEMPLATE_DIRECTORY"/boot/addons
781 if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
782 mkdir -p "${BUILD_OUTPUT}/boot/grub"
784 cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
786 if [ -e ${TEMPLATE_DIRECTORY}/compat/grub/linux.mod ]; then
787 cp "${TEMPLATE_DIRECTORY}"/compat/grub/* "${BUILD_OUTPUT}"/boot/grub/
789 if ! which "grub-mkimage" >/dev/null 2>&1 ; then
790 log "grub-mkimage not found, skipping Grub step therefore." ; eend 0
791 ewarn "grub-mkimage not found, skipping Grub step therefore."
792 ewarn "Please install grub-pc-bin or grub-common >= 1.98+20100804-14." ; eend 0
793 elif ! grub-mkimage --help | grep -q -- --format ; then
794 log "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore." ; eend 0
795 ewarn "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore."
796 ewarn "Please install grub-common >= 1.98+20100804-14 or grub-pc-bin." ; eend 0
798 # copy system grub files if grml-live-compat is not installed
799 cp -a /usr/lib/grub/*-pc/*.mod "${BUILD_OUTPUT}"/boot/grub/
800 cp -a /usr/lib/grub/*-pc/*.o "${BUILD_OUTPUT}"/boot/grub/
801 cp -a /usr/lib/grub/*-pc/*.lst "${BUILD_OUTPUT}"/boot/grub/
802 cp -a /usr/share/grub/ascii.pf2 "${BUILD_OUTPUT}"/boot/grub/
803 grub-mkimage -d /usr/lib/grub/*-pc -o \
804 "${BUILD_OUTPUT}/boot/grub/core.img" biosdisk iso9660 --format=i386-pc
808 if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
809 log "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
810 eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
814 [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
815 cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
817 # adjust boot splash information:
818 RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
819 RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
820 RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
822 if [ -r "$BUILD_OUTPUT"/GRML/grml-version ] ; then
823 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
824 sed -i "s/%DATE%/$DATE/" "$BUILD_OUTPUT"/GRML/grml-version
827 # make sure the squashfs filename is set accordingly:
828 SQUASHFS_NAME="$GRML_NAME.squashfs"
830 if [ -n "$NO_BOOTID" ] ; then
831 log 'Skipping bootid feature as requested via $NO_BOOTID.'
832 einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
834 [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
835 [ -d "$BUILD_OUTPUT"/conf ] || mkdir "$BUILD_OUTPUT"/conf
836 einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
837 log "Generating /conf/bootid.txt with entry ${BOOTID}."
838 echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
842 # adjust all variables in the templates with the according distribution information
843 for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
844 "${BUILD_OUTPUT}"/boot/grub/* ; do
845 if [ -r "${file}" ] ; then
846 sed -i "s/%ARCH%/$ARCH/g" "${file}"
847 sed -i "s/%DATE%/$DATE/g" "${file}"
848 sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g" "${file}"
849 sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g" "${file}"
850 sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g" "${file}"
851 sed -i "s/%GRML_NAME%/$GRML_NAME/g" "${file}"
852 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g" "${file}"
853 sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g" "${file}"
854 sed -i "s/%SHORT_NAME%/$SHORT_NAME/g" "${file}"
855 sed -i "s/%VERSION%/$VERSION/g" "${file}"
857 [ -n "$DEFAULT_BOOTOPTIONS" ] && sed -i "s/ boot=live/ boot=live $DEFAULT_BOOTOPTIONS/" "${file}"
859 if [ -n "$NO_BOOTID" ] ; then
860 sed -i "s/ bootid=%BOOTID%//g" "${file}" # drop bootid bootoption
862 sed -i "s/%BOOTID%/$BOOTID/g" "${file}" # adjust bootid=... argument
867 # adjust bootsplash accordingly but make sure the string has the according lenght
868 SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
869 SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
870 for file in f4 f5 ; do
871 if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
872 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
873 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
877 # generate addon list
878 rm -f "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
879 for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
880 include_name=$(basename "$name")
881 echo "include $include_name" >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
884 if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
885 log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
886 echo "include grmlmain.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
887 echo "include default.cfg" > "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
888 echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
889 echo "include grml.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
891 for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
892 echo "include $(basename $f)" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
895 echo "include options.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
896 if [ ! -n "$NO_ADDONS" ] ; then
897 echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
899 echo "include isoprompt.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
900 echo "include hd.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
901 echo "include hidden.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
902 else # assume we are building a custom distribution:
903 log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
904 einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
905 if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
906 log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
908 einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
912 log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
913 echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
914 [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
918 # use old style console based isolinux method only if requested:
919 if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
920 log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
921 einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
922 if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
923 einfo "include for console.cfg already found, nothing to do."
926 log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
927 einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
928 echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
932 log 'Using graphical boot menu.'
933 if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
934 log "include for vesamenu.cfg already found, nothing to do."
936 log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
937 echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
941 if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
942 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
945 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
946 if ! [ -r "$DPKG_LIST" ] ; then
947 ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
949 einfo "Storing package list information as /GRML/${GRML_NAME}-packages.txt on ISO."
950 cp "$DPKG_LIST" "${BUILD_OUTPUT}/GRML/${GRML_NAME}-packages.txt"
954 # autostart for Windows:
955 if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
956 cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
959 FORCE_ISO_REBUILD=true
960 einfo "Finished execution of stage 'boot'" ; eend 0
964 log 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
965 eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
969 # support installation of local files into the chroot/ISO
970 if [ -n "$CHROOT_INSTALL" ] ; then
971 if ! [ -d "$CHROOT_INSTALL" ] ; then
972 log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
973 ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
975 log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
976 einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
977 rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
979 einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
980 FORCE_ISO_REBUILD=true
984 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
985 log "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
986 ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
987 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
988 log "Skipping stage 'squashfs' as requested via option -q or -N"
989 ewarn "Skipping stage 'squashfs' as requested via option -q or -N" ; eend 0
991 [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
992 # make sure we don't leave (even an empty) base.tgz:
993 [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
995 # if unconfigured default to squashfs-tools' mksquashfs binary
996 if [ -z "$SQUASHFS_BINARY" ] ; then
997 SQUASHFS_BINARY='mksquashfs'
1000 if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
1001 log "Using mksquashfs binary ${SQUASHFS_BINARY}"
1002 einfo "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
1004 log "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
1005 eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
1009 # use sane defaults if $SQUASHFS_OPTIONS isn't set
1010 if [ -z "$SQUASHFS_OPTIONS" ] ; then
1011 # use blocksize 256k as this gives best result with regards to time + compression
1012 SQUASHFS_OPTIONS="-b 256k"
1014 # set lzma/xz compression by default, unless -z option has been specified on command line
1015 if [ -z "$SQUASHFS_ZLIB" ] ; then
1016 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp xz"
1018 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp gzip"
1022 # support exclusion of files via exclude-file:
1023 if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
1024 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE -wildcards"
1027 # get rid of unnecessary files when building grml-small for final release:
1028 if echo "$CLASSES" | grep -q GRML_SMALL ; then
1029 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
1033 SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
1035 # informational stuff
1036 [ -n "$SQUASHFS_OPTIONS" ] && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
1037 [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
1038 einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
1040 log "$SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS"
1042 if $SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
1043 -noappend $SQUASHFS_OPTIONS 2>"${SQUASHFS_STDERR}" ; then
1044 echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
1045 log "Finished execution of stage 'squashfs' [$(date)]"
1046 einfo "Finished execution of stage 'squashfs'" ; eend 0
1048 log "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1049 log "$(cat $SQUASHFS_STDERR)"
1050 eerror "Error: there was a critical error executing stage 'squashfs':"
1051 cat "${SQUASHFS_STDERR}"
1056 FORCE_ISO_REBUILD=true
1059 # create md5sum file:
1060 if [ -z "$BOOTSTRAP_ONLY" ] ; then
1061 ( cd $BUILD_OUTPUT/GRML &&
1062 find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1066 # ISO_OUTPUT - mkisofs {{{
1067 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1068 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1070 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1071 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1072 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1073 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1076 # Just until http://bts.grml.org/grml/issue945 has been resolved.
1077 # HYBRID_METHOD defaults to manifold, so make sure the default works OOTB.
1078 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1079 log "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1080 ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1081 HYBRID_METHOD='grub2'
1085 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ] ; then
1086 log "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1087 ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1088 elif [ -n "$SKIP_MKISOFS" ] ; then
1089 log "Skipping stage 'iso build' as requested via option -n or -N"
1090 ewarn "Skipping stage 'iso build' as requested via option -n or -N" ; eend 0
1092 mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1094 if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1095 log "Forcing rebuild of ISO because files on ISO have been modified."
1096 einfo "Forcing rebuild of ISO because files on ISO have been modified."
1099 # support mkisofs as well as genisoimage
1100 if which mkisofs >/dev/null 2>&1; then
1102 elif which genisoimage >/dev/null 2>&1; then
1103 MKISOFS='genisoimage'
1105 log "Error: neither mkisofs nor genisoimage available - can not create ISO."
1106 eerror "Error: neither mkisofs nor genisoimage available - can not create ISO." ; eend 1
1111 if cd "$BUILD_OUTPUT" ; then
1112 if [ "$BOOT_METHOD" = "grub2" ]; then
1113 # make a 2048-byte bootsector for El Torito
1114 dd if=/dev/zero of=boot/grub/toriboot.bin bs=512 count=4 2>/dev/null
1115 # those are in 2048-byte sectors, so 1 16 matches 4 63 below
1116 echo 1 16 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -B 11 | \
1117 dd of=boot/grub/toriboot.bin conv=notrunc 2>/dev/null
1119 log "$MKISOFS -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J $BOOT_ARGS -o ${ISO_OUTPUT}/${ISO_NAME} ."
1120 "$MKISOFS" -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1121 -l -r -J $BOOT_ARGS -no-pad \
1122 -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1123 # both of these need core.img there, so it’s easier to write it here
1124 if [ "$BOOT_METHOD" = "grub2" ] || [ "$HYBRID_METHOD" = "grub2" ]; then
1125 # must be <= 30720 bytes
1126 dd if=boot/grub/core.img of="${ISO_OUTPUT}/${ISO_NAME}" \
1127 conv=notrunc bs=512 seek=4 2>/dev/null
1130 # pad the output ISO to multiples of 256 KiB for partition table support
1131 siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1132 cyls=$((siz / 512 / 32 / 16 + 1)) # C=$cyls H=16 S=32
1133 siz=$((cyls * 16 * 32 * 512)) # size after padding
1134 dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1135 of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1137 # support disabling hybrid ISO image
1138 if [ "$HYBRID_METHOD" = "disable" ] ; then\
1139 log "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1140 einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1142 # use isohybrid only on request
1143 elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
1144 if ! which isohybrid >/dev/null 2>&1 ; then
1145 bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1147 log "Creating hybrid ISO file with isohybrid method"
1148 einfo "Creating hybrid ISO file with isohybrid method"
1149 # Notes for consideration:
1150 # "-entry 4 -type 1c"
1151 # * using 4 as the partition number is supposed to help with BIOSes
1152 # that only support USB-Zip boot
1153 # * using 1c (i.e. hidden FAT32 LBA), instead of the default 0x17
1154 # (hidden NTFS, IIRC), as the partition type is sometimes needed
1155 # to get the BIOS even look at the partition created by isohybrid
1156 isohybrid "${ISO_OUTPUT}/${ISO_NAME}"
1159 # by default use our manifold boot method:
1161 # isoinfo is part of both mkisofs and genisoimage so we're good
1162 bootoff=$(isoinfo -l -i "${ISO_OUTPUT}/${ISO_NAME}" | \
1163 sed -n '/^.*\[ *\([0-9]*\)[] ].* ISOLINUX.BIN;1 *$/s//\1/p')
1164 if ! [ -r boot/grub/core.img ] ; then
1165 ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1166 elif [ "${bootoff:-0}" -lt 1 ] ; then
1167 ewarn "isolinux.bin not found on the ISO file, disabling manifold boot"
1169 log "Creating hybrid ISO file with manifold method"
1170 einfo "Creating hybrid ISO file with manifold method"
1171 if [ "$HYBRID_METHOD" = "grub2" ] ; then
1172 # 512 bytes: MBR, partition table, load GRUB 2
1173 echo 4 63 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 4:0x96 -g $cyls:16:32
1175 # read only one but 2048-byte sized (scale: << 2) sector
1176 echo $bootoff $bootoff | \
1177 mksh /usr/share/grml-live/scripts/bootilnx.mksh -A -M 4:0x96 -g $cyls:16:32 -S 2
1178 fi | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1183 # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1184 case $CLASSES in *RELEASE*)
1187 if cd $ISO_OUTPUT ; then
1188 md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1189 touch -r ${ISO_NAME} ${ISO_NAME}.md5
1190 sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1191 touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1200 if [ "$RC" = 0 ] ; then
1201 log "Finished execution of stage 'iso build' [$(date)]"
1202 einfo "Finished execution of stage 'iso build'" ; eend 0
1204 log "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1205 eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1211 # log build information to database if grml-live-db is installed and enabled {{{
1213 if [ -d /usr/share/grml-live-db ] ; then
1216 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1217 [ -n "$DPKG_DATABASE" ] || DPKG_DATABASE=/var/log/grml-live.db
1218 [ -n "$DPKG_DBSCRIPT" ] || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1219 [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1221 if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1222 log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1223 eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1227 # disable by default for now, not sure whether really everyone is using a local db file
1228 #if ! touch "$DPKG_DATABASE" ; then
1229 # eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1233 if ! [ -r "$DPKG_LIST" ] ; then
1234 log "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1235 ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1237 einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1238 log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1239 log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1242 if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1258 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1259 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1261 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1263 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1267 ## END OF FILE #################################################################
1268 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2