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 -A ensure clean build and pack artifacts
43 -b build the ISO without updating the chroot via FAI
44 -B build the ISO without touching the chroot (skips cleanup)
45 -c <classe[s]> classes to be used for building the ISO via FAI
46 -C <configfile> configuration file for grml-live
47 -d <date> use specified date instead of build time as date of release
48 -D <configdir> use specified configuration directory instead of /etc/grml/fai
49 -F force execution without prompting
50 -g <grml_name> set the grml flavour name
51 -h display short usage information and exit
52 -i <iso_name> name of ISO
53 -I <src_directory> directory which provides files that should become
54 part of the chroot/ISO
55 -n skip generation of ISO
56 -N bootstrap (build chroot) only, do not create files for ISO
57 -o <output_directory> main output directory of the build process
59 -r <release_name> release name
60 -s <suite> Debian suite; values: etch, lenny, squeeze, sid
61 -t <template_directory> place of the templates
62 -u update existing chroot instead of rebuilding it from scratch
63 -v <version_number> specify version number of the release
64 -V increase verbosity in the build process
65 -z use ZLIB instead of LZMA/XZ compression
70 $PN -c GRMLBASE,GRML_MEDIUM,I386 -o /dev/shm/grml
71 $PN -c GRMLBASE,GRML_SMALL,REMOVE_DOCS,I386 -g grml-small -v 1.0
72 $PN -c GRMLBASE,GRML_FULL,I386 -i grml_0.0-1.iso -v 0.0-1
73 $PN -c GRMLBASE,GRML_FULL,I386 -s sid -V -r 'grml-live rocks'
75 More details: man grml-live + /usr/share/doc/grml-live/grml-live.html
76 http://grml.org/grml-live/
78 Please send your bug reports and feedback to the grml-team: http://grml.org/bugs/
82 # make sure it's possible to get usage information without being
83 # root or actually executing the script
84 if [ "$1" = '-h' -o "$1" = '--help' ] ; then
86 [ "$(id -u 2>/dev/null)" != 0 ] && echo "Please notice that this script requires root permissions."
91 # some runtime checks {{{
92 # we need root permissions for the build-process:
93 if [ "$(id -u 2>/dev/null)" != 0 ] ; then
94 echo "Error: please run this script with uid 0 (root)." >&2
98 if [ -r /var/run/fai/FAI_INSTALLATION_IN_PROGRESS ] ; then
99 echo "/usr/sbin/fai already running or was aborted before.">&2
100 echo "You may remove /var/run/fai/FAI_INSTALLATION_IN_PROGRESS and try again.">&2
105 if [ -r /var/run/fai/fai_softupdate_is_running ] ; then
106 echo "/usr/sbin/fai softupdate already running or was aborted before.">&2
107 echo "You may remove /var/run/fai/fai_softupdate_is_running and try again.">&2
112 # lsb-functions and configuration stuff {{{
113 # make sure they are not set by default
122 # don't use colors/escape sequences
123 if [ -r /lib/lsb/init-functions ] ; then
124 . /lib/lsb/init-functions
125 ! log_use_fancy_output && NOCOLORS=true
128 if [ -r /etc/grml/lsb-functions ] ; then
129 . /etc/grml/lsb-functions
131 einfo() { echo " [*] $*" ;}
132 eerror() { echo " [!] $*">&2 ;}
133 ewarn() { echo " [x] $*" ;}
135 eindent() { return 0 ;}
136 eoutdent() { return 0 ;}
139 # source main configuration file:
140 LIVE_CONF=/etc/grml/grml-live.conf
144 # umount all directories {{{
146 # make sure we don't leave any mounts - FAI doesn't remove them always
147 umount $CHROOT_OUTPUT/proc 2>/dev/null || /bin/true
148 umount $CHROOT_OUTPUT/sys 2>/dev/null || /bin/true
149 umount $CHROOT_OUTPUT/dev/pts 2>/dev/null || /bin/true
150 umount $CHROOT_OUTPUT/dev 2>/dev/null || /bin/true
151 [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
157 rm -f /var/run/fai/fai_softupdate_is_running \
158 /var/run/fai/FAI_INSTALLATION_IN_PROGRESS
159 [ -n "$SQUASHFS_STDERR" ] && rm -rf "$SQUASHFS_STDERR"
161 [ -n "$1" ] && EXIT="$1" || EXIT="1"
162 [ -n "$2" ] && eerror "$2">&2
163 if [ -n "$PACK_ARTIFACTS" ]; then
166 [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && rm -r "${CHROOT_OUTPUT}"
167 [ -n "${BUILD_OUTPUT}" -a -d "${BUILD_OUTPUT}" ] && rm -r "${BUILD_OUTPUT}"
170 log "------------------------------------------------------------------------------"
173 trap bailout 1 2 3 3 6 9 14 15
177 # some important functions {{{
180 # usage: log "string to log"
181 log() { echo "$*" >> $LOGFILE ; }
183 # cut string at character number int = $1
184 # usage: cut_string 5 "1234567890" will output "12345"
186 [ -n "$2" ] || return 1
187 echo "$2" | head -c "$1"; echo -ne "\n"
190 # prepend int = $1 spaces before string = $2
191 # usage: extend_string_begin 5 "123" will output " 123"
192 extend_string_begin() {
193 [ -n "$2" ] || return 1
194 local COUNT="$(echo $2 | wc -c)"
195 local FILL="$(expr $COUNT - $1)"
196 while [ "$FILL" -gt 1 ] ; do
198 local FILL=$(expr $FILL - 1)
200 while [ "$FILL" -lt 1 ] ; do
202 local FILL=$(expr $FILL + 1)
204 echo "$2" | head -c "$1"; echo -ne "\n"
207 # append int = $1 spaces to string = $2
208 # usage: extend_string_begin 5 "123" will output "123 "
209 extend_string_end() {
210 [ -n "$2" ] || return 1
211 echo -n "$2" | head -c "$1"
212 local COUNT="$(echo $2 | wc -c)"
213 local FILL="$(expr $COUNT - $1)"
214 while [ "$FILL" -gt 1 ] ; do
216 local FILL=$(expr $FILL - 1)
218 while [ "$FILL" -lt 1 ] ; do
220 local FILL=$(expr $FILL + 1)
225 # Copy addonfile $1 from either
226 # * the chroot (via $2, the system path),
227 # * or from TEMPLATE_DIRECTORY/compat (if exists),
228 # * or from the host system (again, using $2),
229 # or warn about the missing file.
232 # * We assume that the chroot always has a "good" version of
233 # the file. Also it makes sources handling easier.
234 # * On unstable, we Recommend the Debian packages containing
235 # these files. The user can override them by putting his
236 # "better" version into the chroot.
237 # * On stable, the Debian packages are probably not available,
238 # or outdated, so we look in TEMPLATE_DIRECTORY/compat first, where
239 # our grml-live-compat package installs current file versions.
241 DEST="${BUILD_OUTPUT}/boot/$3"
242 if [ ! -d "${DEST}/" ]; then
245 if [ -e "$CHROOT_OUTPUT/$2/$1" ]; then
246 log "Copying $1 from chroot"
247 cp "$CHROOT_OUTPUT/$2/$1" "${DEST}/"
250 if [ -e "${TEMPLATE_DIRECTORY}/compat/$3/$1" ]; then
251 log "Copying $1 from grml-live-compat"
252 cp "${TEMPLATE_DIRECTORY}/compat/$3/$1" "${DEST}/"
255 if [ -e "$2/$1" ]; then
256 log "Copying $1 from system"
257 cp "$2/$1" "${DEST}/"
261 msg="Missing addon file: \"$1\""
262 ewarn "$msg" ; eend 1
263 log "copy_addon_file: $msg"
267 # read local (non-packaged) configuration {{{
268 LOCAL_CONFIG=/etc/grml/grml-live.local
269 if [ -r "$LOCAL_CONFIG" ] ; then
276 # command line parsing {{{
277 while getopts "a:C:c:d:D:g:i:I:o:r:s:t:v:AbBFnNquVz" opt; do
280 A) PACK_ARTIFACTS=1 ;;
283 c) CLASSES="$OPTARG" ;;
284 C) CONFIG="$OPTARG" ;;
286 D) GRML_FAI_CONFIG="$OPTARG" ;;
287 g) GRML_NAME="$OPTARG" ;;
288 i) ISO_NAME="$OPTARG" ;;
289 I) CHROOT_INSTALL="$OPTARG" ;;
291 N) BOOTSTRAP_ONLY=1; SKIP_MKISOFS=1; SKIP_MKSQUASHFS=1 ;;
292 o) OUTPUT="$OPTARG" ;;
293 q) SKIP_MKSQUASHFS=1 ;;
294 r) RELEASENAME="$OPTARG" ;;
295 s) SUITE="$OPTARG" ;;
296 t) TEMPLATE_DIRECTORY="$OPTARG";;
297 v) VERSION="$OPTARG" ;;
301 z) SQUASHFS_ZLIB=1 ;;
302 ?) echo "invalid option -$OPTARG" >&2; bailout 1 ;;
305 shift $(($OPTIND - 1)) # set ARGV to the first not parsed commandline parameter
308 # assume sane defaults (if not set already) {{{
309 [ -n "$ARCH" ] || ARCH="$(dpkg --print-architecture)"
310 [ -n "$BOOT_METHOD" ] || BOOT_METHOD='isolinux'
311 [ -n "$CLASSES" ] || CLASSES="GRMLBASE,GRML_MEDIUM,I386"
312 [ -n "$DATE" ] || DATE="$(date +%Y-%m-%d)"
313 [ -n "$DISTRI_INFO" ] || DISTRI_INFO='Grml - Live Linux for system administrators '
314 [ -n "$DISTRI_NAME" ] || DISTRI_NAME="grml"
315 [ -n "$DISTRI_SPLASH" ] || DISTRI_SPLASH='grml.png'
316 [ -n "$FORCE_ISO_REBUILD" ] || FORCE_ISO_REBUILD="false"
317 [ -n "$GRML_FAI_CONFIG" ] || GRML_FAI_CONFIG='/etc/grml/fai'
318 [ -n "$GRML_NAME" ] || GRML_NAME='grml'
319 [ -n "$HOSTNAME" ] || HOSTNAME='grml'
320 [ -n "$HYBRID_METHOD" ] || HYBRID_METHOD='manifold'
321 [ -n "$NFSROOT_CONF" ] || NFSROOT_CONF="${GRML_FAI_CONFIG}/make-fai-nfsroot.conf"
322 [ -n "$RELEASENAME" ] || RELEASENAME='grml-live rocks'
323 [ -n "$SOURCES_LIST_OUTPUT" ] || SOURCES_LIST_OUTPUT="${GRML_FAI_CONFIG}/config/files/etc/apt/sources.list/GRML_LIVE_SOURCES_LIST"
324 [ -n "$SQUASHFS_EXCLUDES_FILE" ] || SQUASHFS_EXCLUDES_FILE="${GRML_FAI_CONFIG}/config/grml/squashfs-excludes"
325 [ -n "$SUITE" ] || SUITE='squeeze'
326 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
327 [ -n "$USERNAME" ] || USERNAME='grml'
328 [ -n "$VERSION" ] || VERSION='0.0.1'
330 # output specific stuff, depends on $OUTPUT (iff not set):
331 [ -n "$OUTPUT" ] || OUTPUT='/grml/grml-live'
332 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
333 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
334 [ -n "$CHROOT_ARCHIVE" ] || CHROOT_ARCHIVE="$OUTPUT/$(basename $CHROOT_OUTPUT).tgz"
335 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
336 [ -n "$LOG_OUTPUT" ] || LOG_OUTPUT="$OUTPUT/grml_logs"
339 # some misc checks before executing FAI {{{
340 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
341 specify it on the command line using the -c option."
342 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
343 specify it on the command line using the -o option."
345 # trim characters that are known to cause problems inside $GRML_NAME;
346 # for example isolinux does not like '-' inside the directory name
347 [ -n "$GRML_NAME" ] && export SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
349 # export variables to have them available in fai scripts:
350 [ -n "$GRML_NAME" ] && export GRML_NAME="$GRML_NAME"
351 [ -n "$RELEASENAME" ] && export RELEASENAME="$RELEASENAME"
354 # ZERO_LOGFILE - check for backwards compatibility reasons {{{
355 # this was default behaviour until grml-live 0.9.34:
356 if [ -n "$ZERO_LOGFILE" ] ; then
357 PRESERVE_LOGFILE='' # make sure it's cleaned then
358 ewarn "Please consider disabling the \$ZERO_LOGFILE option as grml-live clears..."
359 ewarn "... the logfile $LOGFILE by default (unless \$PRESERVE_LOGFILE is set) nowadays."
364 # ask user whether the setup is ok {{{
365 if [ -z "$FORCE" ] ; then
367 echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
369 echo " FAI classes: $CLASSES"
370 [ -r "$LOCAL_CONFIG" ] && echo " Local config: /etc/grml/grml-live.local"
371 [ -n "$CONFIG" ] && echo " Configuration: $CONFIG"
372 [ -n "$GRML_FAI_CONFIG" ] && echo " Config directory: $GRML_FAI_CONFIG"
373 echo " main directory: $OUTPUT"
374 [ -n "$CHROOT_OUTPUT" ] && echo " Chroot target: $CHROOT_OUTPUT"
375 [ -n "$BUILD_OUTPUT" ] && echo " Build target: $BUILD_OUTPUT"
376 [ -n "$ISO_OUTPUT" ] && echo " ISO target: $ISO_OUTPUT"
377 [ -n "$GRML_NAME" ] && echo " Grml name: $GRML_NAME"
378 [ -n "$RELEASENAME" ] && echo " Release name: $RELEASENAME"
379 [ -n "$DATE" ] && echo " Build date: $DATE"
380 [ -n "$VERSION" ] && echo " Grml version: $VERSION"
381 [ -n "$SUITE" ] && echo " Debian suite: $SUITE"
382 [ -n "$ARCH" ] && echo " Architecture: $ARCH"
383 [ -n "$BOOT_METHOD" ] && echo " Boot method: $BOOT_METHOD"
384 [ -n "$HYBRID_METHOD" ] && echo " Hybrid method: $HYBRID_METHOD"
385 [ -n "$TEMPLATE_DIRECTORY" ] && echo " Template files: $TEMPLATE_DIRECTORY"
386 [ -n "$CHROOT_INSTALL" ] && echo " Install files from directory to chroot: $CHROOT_INSTALL"
387 [ -n "$BOOTID" ] && echo " Boot identifier: $BOOTID"
388 [ -n "$NO_BOOTID" ] && echo " Skipping bootid feature."
389 [ -n "$DEFAULT_BOOTOPTIONS" ] && echo " Adding default bootoptions: \"$DEFAULT_BOOTOPTIONS\""
390 [ -n "$FAI_ARGS" ] && echo " Additional arguments for FAI: $FAI_ARGS"
391 [ -n "$LOGFILE" ] && echo " Logging to file: $LOGFILE"
392 [ -n "$SQUASHFS_ZLIB" ] && echo " Using ZLIB (instead of LZMA/XZ) compression."
393 [ -n "$SQUASHFS_OPTIONS" ] && echo " Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
394 [ -n "$VERBOSE" ] && echo " Using VERBOSE mode."
395 [ -n "$PACK_ARTIFACTS" ] && echo " Will prepare packed artifacts and ensure clean build."
396 [ -n "$UPDATE" ] && echo " Executing UPDATE instead of fresh installation."
397 if [ -n "$BOOTSTRAP_ONLY" ] ; then
398 echo " Bootstrapping only and not building (files for) ISO."
400 [ -n "$SKIP_MKSQUASHFS" ] && echo " Skipping creation of SQUASHFS file."
401 [ -n "$SKIP_MKISOFS" ] && echo " Skipping creation of ISO file."
402 [ -n "$BUILD_ONLY" ] && echo " Executing BUILD_ONLY instead of fresh installation or UPDATE."
403 [ -n "$BUILD_DIRTY" ] && echo " Executing BUILD_DIRTY to leave chroot untouched."
406 echo -n "Is this ok for you? [y/N] "
408 if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
409 bailout 1 "Exiting as requested."
415 # clean up before start {{{
416 if [ -n "${PACK_ARTIFACTS}" ]; then
417 echo "Wiping old artifacts"
418 [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && rm -r "${CHROOT_OUTPUT}"
419 [ -n "${CHROOT_ARCHIVE}" -a -d "${CHROOT_ARCHIVE}" ] && rm -r "${CHROOT_ARCHIVE}"
420 [ -n "${BUILD_OUTPUT}" -a -d "${BUILD_OUTPUT}" ] && rm -r "${BUILD_OUTPUT}"
421 [ -n "${ISO_OUTPUT}" -a -d "${ISO_OUTPUT}" ] && rm -r "${ISO_OUTPUT}"
422 [ -n "${LOG_OUTPUT}" -a -d "${LOG_OUTPUT}" ] && rm -r "${LOG_OUTPUT}"
426 # create log file {{{
427 [ -n "$LOGFILE" ] || LOGFILE=${LOG_OUTPUT}/grml-live.log
428 mkdir -p $(dirname "${LOGFILE}")
430 chown root:adm $LOGFILE
434 # clean/zero/remove logfiles {{{
436 if [ -n "$PRESERVE_LOGFILE" ] ; then
437 echo "Preserving logfile $LOGFILE as requested via \$PRESERVE_LOGFILE"
439 # make sure it is empty (as it is e.g. appended to grml-live-db)
443 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
444 if [ -d /var/log/fai/"$HOSTNAME" ] ; then
445 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
446 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
447 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
448 rm -f /var/log/fai/"$HOSTNAME"/last \
449 /var/log/fai/"$HOSTNAME"/last-dirinstall \
450 /var/log/fai/"$HOSTNAME"/last-softupdate
455 # source config and startup {{{
456 if [ -n "$CONFIG" ] ; then
457 if ! [ -f "$CONFIG" ] ; then
458 log "Error: $CONFIG could not be read. Exiting. [$(date)]"
459 eerror "Error: $CONFIG could not be read. Exiting." ; eend 1
462 log "Sourcing $CONFIG"
467 start_seconds=$(cut -d . -f 1 /proc/uptime)
468 log "------------------------------------------------------------------------------"
469 log "Starting grml-live [${GRML_LIVE_VERSION}] run on $(date)"
470 if [ -n "$LOCAL_CONFIG" ]; then
471 log "Using local config file: $LOCAL_CONFIG"
473 log "Executed grml-live command line:"
476 einfo "Logging actions to logfile $LOGFILE"
479 # on-the-fly configuration {{{
480 mkdir -p "$(dirname $SOURCES_LIST_OUTPUT)" # might not be present in -D config space
482 cat > "$SOURCES_LIST_OUTPUT" << EOF
483 # NOTE: This file is *NOT* meant for manual customisation! This file is
484 # installed temporarily only by grml-live and will be overriden in the
485 # installation and configuration process then.
488 if [ -n "$MIRROR_DIRECTORY" ] ; then
489 if ! [ -d "$MIRROR_DIRECTORY/debian" ] ; then
490 log "Error: $MIRROR_DIRECTORY/debian does not seem to exist. Exiting. [$(date)]"
491 eerror "Error: $MIRROR_DIRECTORY/debian does not seem to exist. Exiting." ; eend 1
494 echo "$MIRROR_SOURCES" >> "$SOURCES_LIST_OUTPUT"
497 if [ -n "$FAI_DEBOOTSTRAP" ] ; then
498 sed "s#^FAI_DEBOOTSTRAP=.*#FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"#" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
501 # does this suck? YES!
502 # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
504 unstable) SUITE='sid' ;;
505 # make sure that we *NEVER* write any broken suite name to sources.list,
506 # otherwise we won't be able to adjust it one next (correct) execution
514 *) echo "Sorry, $SUITE is not a valid Debian suite, exiting.">&2; bailout 1 ;;
516 export SUITE # make sure it's available in FAI scripts
518 if [ -n "${GRML_LIVE_SOURCES:-}" ] ; then
519 DIST=" etch\| stable\| lenny\| squeeze\| wheezy\| testing\| sid\| unstable"
520 echo "# generated based on \$GRML_LIVE_SOURCES by grml-live
521 $GRML_LIVE_SOURCES" | \
522 sed -e "s/\(^deb .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/;
523 s/\(^deb-src .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/" >> "$SOURCES_LIST_OUTPUT"
525 cat >> "$SOURCES_LIST_OUTPUT" << EOF
526 # generated by grml-live
527 deb http://deb.grml.org/ grml-stable main
528 deb http://deb.grml.org/ grml-testing main
529 deb http://cdn.debian.net/debian $SUITE main contrib non-free
533 # notice: activate grml-live pool when building against unstable or testing:
534 if grep -qwe unstable -qwe sid -qwe testing -qwe wheezy "$SOURCES_LIST_OUTPUT" ; then
535 grep -q 'grml-live.*main' "$SOURCES_LIST_OUTPUT" || \
536 grep grml-stable "$SOURCES_LIST_OUTPUT" | \
537 sed 's/grml-stable/grml-live/' >> "$SOURCES_LIST_OUTPUT"
539 grep -q 'grml-live.*main' "$SOURCES_LIST_OUTPUT" && \
540 sed -i 's/.*grml-live.*main/# removed grml-live repository/' "$SOURCES_LIST_OUTPUT"
543 for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" "$NFSROOT_CONF" ; do
544 if [ -n "$file" ] ; then
545 sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
549 # validate whether the specified architecture class matches the
550 # architecture (option), otherwise installation of kernel will fail
551 if echo $CLASSES | grep -qi i386 ; then
552 if ! [[ "$ARCH" == "i386" ]] ; then
553 log "Error: You specified the I386 class but are trying to build something else (AMD64?)."
554 eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
555 eerror "Tip: Either invoke grml-live with '-a i386' or adjust the architecture class. Exiting."
559 elif echo $CLASSES | grep -qi amd64 ; then
560 if ! [[ "$ARCH" == "amd64" ]] ; then
561 log "Error: You specified the AMD64 class but are trying to build something else (I386?)."
562 eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
563 eerror "Tip: Either invoke grml-live with '-a amd64' or adjust the architecture class. Exiting."
569 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
570 sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
572 sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
576 # CHROOT_OUTPUT - execute FAI {{{
577 if [ -n "$BUILD_DIRTY" ]; then
578 log "Skipping stage 'fai' as requested via option -B"
579 ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
581 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
583 # provide inform fai about the ISO we build
584 [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
585 echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
586 [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
587 [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
589 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
590 FAI_ACTION=softupdate
592 FAI_ACTION=dirinstall
595 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
596 if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
597 log "Error: does not look like you have a working chroot. Updating/building not possible."
598 eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
604 if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
605 log "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
606 ewarn "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
608 mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
610 if [ -n "${MIRROR_DIRECTORY}" ] ; then
611 mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
612 mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
615 # tell dpkg to use "unsafe io" during the build
616 [ -d "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d" ] || mkdir -p "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d"
617 echo force-unsafe-io > "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
619 log "Executed FAI command line:"
620 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"
621 BUILD_ONLY="$BUILD_ONLY" BOOTSTRAP_ONLY="$BOOTSTRAP_ONLY" fai $VERBOSE \
622 -C "$GRML_FAI_CONFIG" -s "file:///$GRML_FAI_CONFIG/config" -c"$CLASSES" \
623 -u "$HOSTNAME" "$FAI_ACTION" "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
624 RC="$PIPESTATUS" # notice: bash-only
626 rm -f "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
628 FORCE_ISO_REBUILD=true
630 if [ "$RC" != 0 ] ; then
631 log "Error: critical error while executing fai [exit code ${RC}]. Exiting."
632 eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
635 einfo "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
636 log "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
637 echo "$GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]" > $CHROOT_OUTPUT/etc/grml_version
638 chmod 644 $CHROOT_OUTPUT/etc/grml_version
639 einfo "Rebuilding initramfs"
640 # make sure new /etc/grml_version reaches initramfs, iterate over all
641 # present kernel versions (note: we can't really handle more than one
642 # kernel version anyway right now)
643 # chroot $CHROOT_OUTPUT update-initramfs -u -t => might break when using kernel-package :(
644 for initrd in "$(basename $CHROOT_OUTPUT/boot/vmlinuz-*)" ; do
645 if ! chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -c ; then
646 einfo "Creating fresh initrd did not work, trying update instead:"
647 log "Creating fresh initrd did not work, trying update instead:"
648 chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -u
654 # move fai logs into grml_logs directory
655 mkdir -p "$LOG_OUTPUT"/fai/
656 cp -r "$CHROOT_OUTPUT"/var/log/fai/"$HOSTNAME"/last/* "$LOG_OUTPUT"/fai/
657 chown root:adm "$LOG_OUTPUT"/fai/*
658 chmod 664 "$LOG_OUTPUT"/fai/*
659 rm -rf "$CHROOT_OUTPUT"/var/log/fai
661 # Remove all FAI logs from chroot if class RELEASE is used:
662 rm -f "$CHROOT_OUTPUT"/var/log/install_packages.list
666 # notice: 'fai dirinstall' does not seem to exit appropriate, so:
668 CHECKLOG=/var/log/fai/$HOSTNAME/last
669 if [ -r "$CHECKLOG/software.log" ] ; then
670 # 1 errors during executing of commands
671 grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
672 grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
673 grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
674 grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
675 grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
678 if [ -r "$CHECKLOG/shell.log" ] ; then
679 grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=6
682 if [ -n "$ERROR" ] ; then
683 log "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
684 eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
685 eerror "Note: check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
689 log "Finished execution of stage 'fai dirinstall' [$(date)]"
690 einfo "Finished execution of stage 'fai dirinstall'"
693 einfo "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
694 log "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
700 # package validator {{{
701 CHECKLOG=/var/log/fai/$HOSTNAME/last
703 if [ -r "$CHECKLOG/package_errors.log" ] && grep -q '[a-z]' "$CHECKLOG/package_errors.log" ; then
705 if [ -n "$EXIT_ON_MISSING_PACKAGES" -a -z "$BUILD_DIRTY" ] ; then
706 eerror "The following packages were requested for installation but could not be processed:"
707 cat $CHECKLOG/package_errors.log
708 eerror "... exiting as requested via \$EXIT_ON_MISSING_PACKAGES."
712 ewarn "The following packages were requested for installation but could not be processed:"
713 cat $CHECKLOG/package_errors.log
719 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
720 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
721 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
724 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
725 if [ -n "$BOOTSTRAP_ONLY" ] ; then
726 log "Skipping stage 'boot' as building with bootstrap only."
727 ewarn "Skipping stage 'boot' as building with bootstrap only." ; eend 0
729 if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
730 log "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already."
731 ewarn "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already." ; eend 0
734 [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
735 [ -d "$BUILD_OUTPUT"/boot/"${SHORT_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
737 # if we don't have an initrd we a) can't boot and b) there was an error
738 # during build, so check for the file:
739 INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
740 if [ -n "$INITRD" ] ; then
741 cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.gz
742 find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
744 log "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
745 eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
749 KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
750 if [ -n "$KERNEL_IMAGE" ] ; then
751 cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/linux26
753 log "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
754 eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
758 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
759 if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
760 log "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
761 eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
765 # copy _required_ isolinux files
766 for file in ifcpu64.c32 isolinux.bin vesamenu.c32; do
767 copy_addon_file "${file}" /usr/lib/syslinux isolinux
770 # *always* copy files to output directory so the variables
771 # get adjusted according to the build.
772 cp ${TEMPLATE_DIRECTORY}/boot/isolinux/* "$BUILD_OUTPUT"/boot/isolinux/
774 if [ -n "$NO_ADDONS" ] ; then
775 log "Skipping installation of boot addons as requested via \$NO_ADDONS."
776 einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
778 if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
779 log "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
780 ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
782 # copy addons from system packages or grml-live-compat
783 copy_addon_file ipxe.lkrn /usr/lib/ipxe addons
784 copy_addon_file pci.ids /usr/share/misc addons
785 copy_addon_file memtest86+.bin /boot addons
786 for file in memdisk chain.c32 hdt.c32 menu.c32; do
787 copy_addon_file "${file}" /usr/lib/syslinux addons
790 # make memtest filename FAT16/8.3 compatible
791 mv "${BUILD_OUTPUT}/boot/addons/memtest86+.bin" \
792 "${BUILD_OUTPUT}/boot/addons/memtest"
794 # copy only files so we can handle bsd4grml on its own
795 for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
796 test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
799 if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
800 log "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
801 einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
803 if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
804 cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
806 log "Missing addon file: bsd4grml"
807 ewarn "Missing addon file: bsd4grml" ; eend 0
811 fi # no "$TEMPLATE_DIRECTORY"/boot/addons
814 if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
815 mkdir -p "${BUILD_OUTPUT}/boot/grub"
817 cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
819 if [ -e ${TEMPLATE_DIRECTORY}/compat/grub/linux.mod ]; then
820 cp "${TEMPLATE_DIRECTORY}"/compat/grub/* "${BUILD_OUTPUT}"/boot/grub/
822 if ! which "grub-mkimage" >/dev/null 2>&1 ; then
823 log "grub-mkimage not found, skipping Grub step therefore." ; eend 0
824 ewarn "grub-mkimage not found, skipping Grub step therefore."
825 ewarn "Please install grub-pc-bin or grub-common >= 1.98+20100804-14." ; eend 0
826 elif ! grub-mkimage --help | grep -q -- --format ; then
827 log "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore." ; eend 0
828 ewarn "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore."
829 ewarn "Please install grub-common >= 1.98+20100804-14 or grub-pc-bin." ; eend 0
831 # copy system grub files if grml-live-compat is not installed
832 cp -a /usr/lib/grub/*-pc/*.mod "${BUILD_OUTPUT}"/boot/grub/
833 cp -a /usr/lib/grub/*-pc/*.o "${BUILD_OUTPUT}"/boot/grub/
834 cp -a /usr/lib/grub/*-pc/*.lst "${BUILD_OUTPUT}"/boot/grub/
835 cp -a /usr/share/grub/ascii.pf2 "${BUILD_OUTPUT}"/boot/grub/
836 grub-mkimage -d /usr/lib/grub/*-pc -o \
837 "${BUILD_OUTPUT}/boot/grub/core.img" biosdisk iso9660 --format=i386-pc
841 if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
842 log "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
843 eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
847 [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
848 cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
850 # adjust boot splash information:
851 RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
852 RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
853 RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
855 if [ -r "$BUILD_OUTPUT"/GRML/grml-version ] ; then
856 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
857 sed -i "s/%DATE%/$DATE/" "$BUILD_OUTPUT"/GRML/grml-version
860 # make sure the squashfs filename is set accordingly:
861 SQUASHFS_NAME="$GRML_NAME.squashfs"
863 if [ -n "$NO_BOOTID" ] ; then
864 log 'Skipping bootid feature as requested via $NO_BOOTID.'
865 einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
867 [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
868 [ -d "$BUILD_OUTPUT"/conf ] || mkdir "$BUILD_OUTPUT"/conf
869 einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
870 log "Generating /conf/bootid.txt with entry ${BOOTID}."
871 echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
875 # adjust all variables in the templates with the according distribution information
876 for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
877 "${BUILD_OUTPUT}"/boot/grub/* ; do
878 if [ -r "${file}" ] ; then
879 sed -i "s/%ARCH%/$ARCH/g" "${file}"
880 sed -i "s/%DATE%/$DATE/g" "${file}"
881 sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g" "${file}"
882 sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g" "${file}"
883 sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g" "${file}"
884 sed -i "s/%GRML_NAME%/$GRML_NAME/g" "${file}"
885 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g" "${file}"
886 sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g" "${file}"
887 sed -i "s/%SHORT_NAME%/$SHORT_NAME/g" "${file}"
888 sed -i "s/%VERSION%/$VERSION/g" "${file}"
890 [ -n "$DEFAULT_BOOTOPTIONS" ] && sed -i "s/ boot=live/ boot=live $DEFAULT_BOOTOPTIONS/" "${file}"
892 if [ -n "$NO_BOOTID" ] ; then
893 sed -i "s/ bootid=%BOOTID%//g" "${file}" # drop bootid bootoption
895 sed -i "s/%BOOTID%/$BOOTID/g" "${file}" # adjust bootid=... argument
900 # adjust bootsplash accordingly but make sure the string has the according lenght
901 SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
902 SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
903 for file in f4 f5 ; do
904 if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
905 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
906 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
910 # generate addon list
911 rm -f "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
912 for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
913 include_name=$(basename "$name")
914 echo "include $include_name" >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
917 if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
918 log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
919 echo "include grmlmain.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
920 echo "include default.cfg" > "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
921 echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
922 echo "include grml.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
924 for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
925 echo "include $(basename $f)" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
928 echo "include options.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
929 if [ ! -n "$NO_ADDONS" ] ; then
930 echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
932 echo "include isoprompt.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
933 echo "include hd.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
934 echo "include hidden.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
935 else # assume we are building a custom distribution:
936 log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
937 einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
938 if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
939 log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
941 einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
945 log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
946 echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
947 [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
951 # use old style console based isolinux method only if requested:
952 if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
953 log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
954 einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
955 if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
956 einfo "include for console.cfg already found, nothing to do."
959 log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
960 einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
961 echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
965 log 'Using graphical boot menu.'
966 if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
967 log "include for vesamenu.cfg already found, nothing to do."
969 log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
970 echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
974 if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
975 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
978 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
979 if ! [ -r "$DPKG_LIST" ] ; then
980 ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
982 einfo "Storing package list information as /GRML/${GRML_NAME}-packages.txt on ISO."
983 cp "$DPKG_LIST" "${BUILD_OUTPUT}/GRML/${GRML_NAME}-packages.txt"
987 # autostart for Windows:
988 if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
989 cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
992 FORCE_ISO_REBUILD=true
993 einfo "Finished execution of stage 'boot'" ; eend 0
997 log 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
998 eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
1002 # support installation of local files into the chroot/ISO
1003 if [ -n "$CHROOT_INSTALL" ] ; then
1004 if ! [ -d "$CHROOT_INSTALL" ] ; then
1005 log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1006 ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1008 log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1009 einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1010 rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
1012 einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
1013 FORCE_ISO_REBUILD=true
1017 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
1018 log "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
1019 ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
1020 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
1021 log "Skipping stage 'squashfs' as requested via option -q or -N"
1022 ewarn "Skipping stage 'squashfs' as requested via option -q or -N" ; eend 0
1024 [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
1025 # make sure we don't leave (even an empty) base.tgz:
1026 [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
1028 # if unconfigured default to squashfs-tools' mksquashfs binary
1029 if [ -z "$SQUASHFS_BINARY" ] ; then
1030 SQUASHFS_BINARY='mksquashfs'
1033 if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
1034 log "Using mksquashfs binary ${SQUASHFS_BINARY}"
1035 einfo "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
1037 log "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
1038 eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
1042 # use sane defaults if $SQUASHFS_OPTIONS isn't set
1043 if [ -z "$SQUASHFS_OPTIONS" ] ; then
1044 # use blocksize 256k as this gives best result with regards to time + compression
1045 SQUASHFS_OPTIONS="-b 256k"
1047 # set lzma/xz compression by default, unless -z option has been specified on command line
1048 if [ -z "$SQUASHFS_ZLIB" ] ; then
1049 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp xz"
1051 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp gzip"
1055 # support exclusion of files via exclude-file:
1056 if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
1057 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE -wildcards"
1060 # get rid of unnecessary files when building grml-small for final release:
1061 if echo "$CLASSES" | grep -q GRML_SMALL ; then
1062 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
1066 SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
1068 # informational stuff
1069 [ -n "$SQUASHFS_OPTIONS" ] && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
1070 [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
1071 einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
1073 log "$SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS"
1075 if $SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
1076 -noappend $SQUASHFS_OPTIONS 2>"${SQUASHFS_STDERR}" ; then
1077 echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
1078 log "Finished execution of stage 'squashfs' [$(date)]"
1079 einfo "Finished execution of stage 'squashfs'" ; eend 0
1081 log "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1082 log "$(cat $SQUASHFS_STDERR)"
1083 eerror "Error: there was a critical error executing stage 'squashfs':"
1084 cat "${SQUASHFS_STDERR}"
1089 FORCE_ISO_REBUILD=true
1092 # create md5sum file:
1093 if [ -z "$BOOTSTRAP_ONLY" ] ; then
1094 ( cd $BUILD_OUTPUT/GRML &&
1095 find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1099 # ISO_OUTPUT - mkisofs {{{
1100 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1101 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1103 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1104 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1105 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1106 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1109 # Just until http://bts.grml.org/grml/issue945 has been resolved.
1110 # HYBRID_METHOD defaults to manifold, so make sure the default works OOTB.
1111 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1112 log "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1113 ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1114 HYBRID_METHOD='grub2'
1118 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ] ; then
1119 log "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1120 ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1121 elif [ -n "$SKIP_MKISOFS" ] ; then
1122 log "Skipping stage 'iso build' as requested via option -n or -N"
1123 ewarn "Skipping stage 'iso build' as requested via option -n or -N" ; eend 0
1125 mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1127 if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1128 log "Forcing rebuild of ISO because files on ISO have been modified."
1129 einfo "Forcing rebuild of ISO because files on ISO have been modified."
1132 # support mkisofs as well as genisoimage
1133 if which mkisofs >/dev/null 2>&1; then
1135 elif which genisoimage >/dev/null 2>&1; then
1136 MKISOFS='genisoimage'
1138 log "Error: neither mkisofs nor genisoimage available - can not create ISO."
1139 eerror "Error: neither mkisofs nor genisoimage available - can not create ISO." ; eend 1
1144 if cd "$BUILD_OUTPUT" ; then
1145 if [ "$BOOT_METHOD" = "grub2" ]; then
1146 # make a 2048-byte bootsector for El Torito
1147 dd if=/dev/zero of=boot/grub/toriboot.bin bs=512 count=4 2>/dev/null
1148 # those are in 2048-byte sectors, so 1 16 matches 4 63 below
1149 echo 1 16 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -B 11 | \
1150 dd of=boot/grub/toriboot.bin conv=notrunc 2>/dev/null
1152 log "$MKISOFS -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J $BOOT_ARGS -o ${ISO_OUTPUT}/${ISO_NAME} ."
1153 "$MKISOFS" -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1154 -l -r -J $BOOT_ARGS -no-pad \
1155 -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1156 # both of these need core.img there, so it’s easier to write it here
1157 if [ "$BOOT_METHOD" = "grub2" ] || [ "$HYBRID_METHOD" = "grub2" ]; then
1158 # must be <= 30720 bytes
1159 dd if=boot/grub/core.img of="${ISO_OUTPUT}/${ISO_NAME}" \
1160 conv=notrunc bs=512 seek=4 2>/dev/null
1163 # pad the output ISO to multiples of 256 KiB for partition table support
1164 siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1165 cyls=$((siz / 512 / 32 / 16 + 1)) # C=$cyls H=16 S=32
1166 siz=$((cyls * 16 * 32 * 512)) # size after padding
1167 dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1168 of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1170 # support disabling hybrid ISO image
1171 if [ "$HYBRID_METHOD" = "disable" ] ; then\
1172 log "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1173 einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1175 # use isohybrid only on request
1176 elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
1177 if ! which isohybrid >/dev/null 2>&1 ; then
1178 bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1180 log "Creating hybrid ISO file with isohybrid method"
1181 einfo "Creating hybrid ISO file with isohybrid method"
1182 # Notes for consideration:
1183 # "-entry 4 -type 1c"
1184 # * using 4 as the partition number is supposed to help with BIOSes
1185 # that only support USB-Zip boot
1186 # * using 1c (i.e. hidden FAT32 LBA), instead of the default 0x17
1187 # (hidden NTFS, IIRC), as the partition type is sometimes needed
1188 # to get the BIOS even look at the partition created by isohybrid
1189 isohybrid "${ISO_OUTPUT}/${ISO_NAME}"
1192 # by default use our manifold boot method:
1194 # isoinfo is part of both mkisofs and genisoimage so we're good
1195 bootoff=$(isoinfo -l -i "${ISO_OUTPUT}/${ISO_NAME}" | \
1196 sed -n '/^.*\[ *\([0-9]*\)[] ].* ISOLINUX.BIN;1 *$/s//\1/p')
1197 if ! [ -r boot/grub/core.img ] ; then
1198 ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1199 elif [ "${bootoff:-0}" -lt 1 ] ; then
1200 ewarn "isolinux.bin not found on the ISO file, disabling manifold boot"
1202 log "Creating hybrid ISO file with manifold method"
1203 einfo "Creating hybrid ISO file with manifold method"
1204 if [ "$HYBRID_METHOD" = "grub2" ] ; then
1205 # 512 bytes: MBR, partition table, load GRUB 2
1206 echo 4 63 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 4:0x96 -g $cyls:16:32
1208 # read only one but 2048-byte sized (scale: << 2) sector
1209 echo $bootoff $bootoff | \
1210 mksh /usr/share/grml-live/scripts/bootilnx.mksh -A -M 4:0x96 -g $cyls:16:32 -S 2
1211 fi | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1216 # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1217 case $CLASSES in *RELEASE*)
1220 if cd $ISO_OUTPUT ; then
1221 md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1222 touch -r ${ISO_NAME} ${ISO_NAME}.md5
1223 sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1224 touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1233 if [ "$RC" = 0 ] ; then
1234 log "Finished execution of stage 'iso build' [$(date)]"
1235 einfo "Finished execution of stage 'iso build'" ; eend 0
1237 log "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1238 eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1244 # pack artifacts {{{
1245 if [ -n "$PACK_ARTIFACTS" ]; then
1246 log "Packing artifcats"
1247 einfo "Packing artifacts"
1248 [ -f "${CHROOT_ARCHIVE}" ] && rm -r "${CHROOT_ARCHIVE}"
1249 tar -c -a -f ${CHROOT_ARCHIVE} --preserve-permissions -C "$(dirname ${CHROOT_OUTPUT})" "$(basename ${CHROOT_OUTPUT})"
1254 # log build information to database if grml-live-db is installed and enabled {{{
1256 if [ -d /usr/share/grml-live-db ] ; then
1259 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1260 [ -n "$DPKG_DATABASE" ] || DPKG_DATABASE=/var/log/grml-live.db
1261 [ -n "$DPKG_DBSCRIPT" ] || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1262 [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1264 if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1265 log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1266 eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1270 # disable by default for now, not sure whether really everyone is using a local db file
1271 #if ! touch "$DPKG_DATABASE" ; then
1272 # eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1276 if ! [ -r "$DPKG_LIST" ] ; then
1277 log "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1278 ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1280 einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1281 log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1282 log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1285 if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1301 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1302 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1304 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1306 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1310 ## END OF FILE #################################################################
1311 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2