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 -U <username> arrange output to be owned by specified username
64 -v <version_number> specify version number of the release
65 -V increase verbosity in the build process
66 -z use ZLIB instead of LZMA/XZ compression
71 $PN -c GRMLBASE,GRML_FULL,AMD64 -o /dev/shm/grml
72 $PN -c GRMLBASE,GRML_FULL,AMD64 -i grml_0.0-1.iso -v 0.0-1
73 $PN -c GRMLBASE,GRML_FULL,AMD64 -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
152 # certain FAI versions sadly leave a ramdisk behind, so better safe than sorry
153 if [ -x /usr/lib/fai/mkramdisk ] ; then
154 /usr/lib/fai/mkramdisk -u "$(readlink -f ${CHROOT_OUTPUT}/var/lib/dpkg)" >/dev/null 2>&1 || /bin/true
157 umount "${CHROOT_OUTPUT}/grml-live/sources/" 2>/dev/null || /bin/true
158 [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
164 rm -f /var/run/fai/fai_softupdate_is_running \
165 /var/run/fai/FAI_INSTALLATION_IN_PROGRESS
166 [ -n "$SQUASHFS_STDERR" ] && rm -rf "$SQUASHFS_STDERR"
168 [ -n "$1" ] && EXIT="$1" || EXIT="1"
169 [ -n "$2" ] && eerror "$2">&2
170 if [ -n "$PACK_ARTIFACTS" ]; then
173 [ -n "${BUILD_OUTPUT}" -a -d "${BUILD_OUTPUT}" ] && rm -r "${BUILD_OUTPUT}"
174 [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && rm -r "${CHROOT_OUTPUT}"
177 if [ -n "$CHOWN_USER" ]; then
178 log "Setting ownership"
179 einfo "Setting ownership"
180 [ -n "${OUTPUT}" -a -d "${OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${OUTPUT}"
181 [ -n "${BUILD_OUTPUT}" -a -d "${BUILD_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${BUILD_OUTPUT}"
182 [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${CHROOT_OUTPUT}"
183 [ -n "${ISO_OUTPUT}" -a -d "${ISO_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${ISO_OUTPUT}"
184 [ -n "${LOG_OUTPUT}" -a -d "${LOG_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${LOG_OUTPUT}"
185 [ -n "${CHROOT_ARCHIVE}" -a -f "${CHROOT_ARCHIVE}" ] && chown -R "${CHOWN_USER}:" "${CHROOT_ARCHIVE}"
188 log "------------------------------------------------------------------------------"
191 trap bailout 1 2 3 3 6 9 14 15
195 # some important functions {{{
198 # usage: log "string to log"
199 log() { echo "$*" >> $LOGFILE ; }
201 # cut string at character number int = $1
202 # usage: cut_string 5 "1234567890" will output "12345"
204 [ -n "$2" ] || return 1
205 echo "$2" | head -c "$1"; echo -ne "\n"
208 # prepend int = $1 spaces before string = $2
209 # usage: extend_string_begin 5 "123" will output " 123"
210 extend_string_begin() {
211 [ -n "$2" ] || return 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)
222 echo "$2" | head -c "$1"; echo -ne "\n"
225 # append int = $1 spaces to string = $2
226 # usage: extend_string_begin 5 "123" will output "123 "
227 extend_string_end() {
228 [ -n "$2" ] || return 1
229 echo -n "$2" | head -c "$1"
230 local COUNT="$(echo $2 | wc -c)"
231 local FILL="$(expr $COUNT - $1)"
232 while [ "$FILL" -gt 1 ] ; do
234 local FILL=$(expr $FILL - 1)
236 while [ "$FILL" -lt 1 ] ; do
238 local FILL=$(expr $FILL + 1)
243 # Copy addonfile $1 from either
244 # * the chroot (via $2, the system path),
245 # * or from TEMPLATE_DIRECTORY/compat (if exists),
246 # * or from the host system (again, using $2),
247 # or warn about the missing file.
250 # * We assume that the chroot always has a "good" version of
251 # the file. Also it makes sources handling easier.
252 # * On unstable, we Recommend the Debian packages containing
253 # these files. The user can override them by putting his
254 # "better" version into the chroot.
255 # * On stable, the Debian packages are probably not available,
256 # or outdated, so we look in TEMPLATE_DIRECTORY/compat first, where
257 # our grml-live-compat package installs current file versions.
259 DEST="${BUILD_OUTPUT}/boot/$3"
260 if [ ! -d "${DEST}/" ]; then
263 if [ -e "$CHROOT_OUTPUT/$2/$1" ]; then
264 log "Copying $1 from chroot"
265 cp "$CHROOT_OUTPUT/$2/$1" "${DEST}/"
268 if [ -e "${TEMPLATE_DIRECTORY}/compat/$3/$1" ]; then
269 log "Copying $1 from grml-live-compat"
270 cp "${TEMPLATE_DIRECTORY}/compat/$3/$1" "${DEST}/"
273 if [ -e "$2/$1" ]; then
274 log "Copying $1 from system"
275 cp "$2/$1" "${DEST}/"
279 msg="Missing addon file: \"$1\""
280 ewarn "$msg" ; eend 1
281 log "copy_addon_file: $msg"
285 # read local (non-packaged) configuration {{{
286 LOCAL_CONFIG=/etc/grml/grml-live.local
287 if [ -r "$LOCAL_CONFIG" ] ; then
293 if [ -n "${GRML_LIVE_SOURCES:-}" ] ; then
294 eerror "Config variable \$GRML_LIVE_SOURCES is set. This variable has been deprecated."
295 ewarn "Please set up ${GRML_FAI_CONFIG}/config/files/etc/apt/sources.list.d/* instead."
300 # command line parsing {{{
301 while getopts "a:C:c:d:D:g:i:I:o:r:s:t:U:v:AbBFnNquVz" opt; do
304 A) PACK_ARTIFACTS=1 ;;
307 c) CLASSES="$OPTARG" ;;
308 C) CONFIG="$OPTARG" ;;
310 D) GRML_FAI_CONFIG="$OPTARG" ;;
311 g) GRML_NAME="$OPTARG" ;;
312 i) ISO_NAME="$OPTARG" ;;
313 I) CHROOT_INSTALL="$OPTARG" ;;
315 N) BOOTSTRAP_ONLY=1; SKIP_MKISOFS=1; SKIP_MKSQUASHFS=1 ;;
316 o) OUTPUT="$OPTARG" ;;
317 q) SKIP_MKSQUASHFS=1 ;;
318 r) RELEASENAME="$OPTARG" ;;
319 s) SUITE="$OPTARG" ;;
320 t) TEMPLATE_DIRECTORY="$OPTARG";;
321 v) VERSION="$OPTARG" ;;
324 U) CHOWN_USER="$OPTARG" ;;
326 z) SQUASHFS_ZLIB=1 ;;
327 ?) echo "invalid option -$OPTARG" >&2; bailout 1 ;;
330 shift $(($OPTIND - 1)) # set ARGV to the first not parsed commandline parameter
333 # assume sane defaults (if not set already) {{{
334 [ -n "$ARCH" ] || ARCH="$(dpkg --print-architecture)"
335 [ -n "$BOOT_METHOD" ] || BOOT_METHOD='isolinux'
336 [ -n "$CLASSES" ] || CLASSES="GRMLBASE,GRML_FULL,$(echo ${ARCH} | tr 'a-z' 'A-Z')"
337 [ -n "$DATE" ] || DATE="$(date +%Y-%m-%d)"
338 [ -n "$DISTRI_INFO" ] || DISTRI_INFO='Grml - Live Linux for system administrators '
339 [ -n "$DISTRI_NAME" ] || DISTRI_NAME="grml"
340 [ -n "$DISTRI_SPLASH" ] || DISTRI_SPLASH='grml.png'
341 [ -n "$FORCE_ISO_REBUILD" ] || FORCE_ISO_REBUILD="false"
342 [ -n "$GRML_FAI_CONFIG" ] || GRML_FAI_CONFIG='/etc/grml/fai'
343 [ -n "$GRML_NAME" ] || GRML_NAME='grml'
344 [ -n "$HOSTNAME" ] || HOSTNAME='grml'
345 [ -n "$HYBRID_METHOD" ] || HYBRID_METHOD='manifold'
346 [ -n "$NFSROOT_CONF" ] || NFSROOT_CONF="${GRML_FAI_CONFIG}/make-fai-nfsroot.conf"
347 [ -n "$RELEASENAME" ] || RELEASENAME='grml-live rocks'
348 [ -n "$SQUASHFS_EXCLUDES_FILE" ] || SQUASHFS_EXCLUDES_FILE="${GRML_FAI_CONFIG}/config/grml/squashfs-excludes"
349 [ -n "$SUITE" ] || SUITE='squeeze'
350 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
351 [ -n "$USERNAME" ] || USERNAME='grml'
352 [ -n "$VERSION" ] || VERSION='0.0.1'
354 # output specific stuff, depends on $OUTPUT (iff not set):
355 [ -n "$OUTPUT" ] || OUTPUT='/grml/grml-live'
356 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
357 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
358 [ -n "$CHROOT_ARCHIVE" ] || CHROOT_ARCHIVE="$OUTPUT/$(basename $CHROOT_OUTPUT).tgz"
359 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
360 [ -n "$LOG_OUTPUT" ] || LOG_OUTPUT="$OUTPUT/grml_logs"
363 # some misc checks before executing FAI {{{
364 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
365 specify it on the command line using the -c option."
366 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
367 specify it on the command line using the -o option."
369 # trim characters that are known to cause problems inside $GRML_NAME;
370 # for example isolinux does not like '-' inside the directory name
371 [ -n "$GRML_NAME" ] && export SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
373 # export variables to have them available in fai scripts:
374 [ -n "$GRML_NAME" ] && export GRML_NAME="$GRML_NAME"
375 [ -n "$RELEASENAME" ] && export RELEASENAME="$RELEASENAME"
378 # ZERO_LOGFILE - check for backwards compatibility reasons {{{
379 # this was default behaviour until grml-live 0.9.34:
380 if [ -n "$ZERO_LOGFILE" ] ; then
381 PRESERVE_LOGFILE='' # make sure it's cleaned then
382 ewarn "Please consider disabling the \$ZERO_LOGFILE option as grml-live clears..."
383 ewarn "... the logfile $LOGFILE by default (unless \$PRESERVE_LOGFILE is set) nowadays."
388 # ask user whether the setup is ok {{{
389 if [ -z "$FORCE" ] ; then
391 echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
393 echo " FAI classes: $CLASSES"
394 [ -r "$LOCAL_CONFIG" ] && echo " Local config: /etc/grml/grml-live.local"
395 [ -n "$CONFIG" ] && echo " Configuration: $CONFIG"
396 [ -n "$GRML_FAI_CONFIG" ] && echo " Config directory: $GRML_FAI_CONFIG"
397 echo " main directory: $OUTPUT"
398 [ -n "$CHROOT_OUTPUT" ] && echo " Chroot target: $CHROOT_OUTPUT"
399 [ -n "$BUILD_OUTPUT" ] && echo " Build target: $BUILD_OUTPUT"
400 [ -n "$ISO_OUTPUT" ] && echo " ISO target: $ISO_OUTPUT"
401 [ -n "$GRML_NAME" ] && echo " Grml name: $GRML_NAME"
402 [ -n "$RELEASENAME" ] && echo " Release name: $RELEASENAME"
403 [ -n "$DATE" ] && echo " Build date: $DATE"
404 [ -n "$VERSION" ] && echo " Grml version: $VERSION"
405 [ -n "$SUITE" ] && echo " Debian suite: $SUITE"
406 [ -n "$ARCH" ] && echo " Architecture: $ARCH"
407 [ -n "$BOOT_METHOD" ] && echo " Boot method: $BOOT_METHOD"
408 [ -n "$HYBRID_METHOD" ] && echo " Hybrid method: $HYBRID_METHOD"
409 [ -n "$TEMPLATE_DIRECTORY" ] && echo " Template files: $TEMPLATE_DIRECTORY"
410 [ -n "$CHROOT_INSTALL" ] && echo " Install files from directory to chroot: $CHROOT_INSTALL"
411 [ -n "$BOOTID" ] && echo " Boot identifier: $BOOTID"
412 [ -n "$NO_BOOTID" ] && echo " Skipping bootid feature."
413 [ -n "$CHOWN_USER" ] && echo " Output owner: $CHOWN_USER"
414 [ -n "$DEFAULT_BOOTOPTIONS" ] && echo " Adding default bootoptions: \"$DEFAULT_BOOTOPTIONS\""
415 [ -n "$FAI_ARGS" ] && echo " Additional arguments for FAI: $FAI_ARGS"
416 [ -n "$LOGFILE" ] && echo " Logging to file: $LOGFILE"
417 [ -n "$SQUASHFS_ZLIB" ] && echo " Using ZLIB (instead of LZMA/XZ) compression."
418 [ -n "$SQUASHFS_OPTIONS" ] && echo " Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
419 [ -n "$VERBOSE" ] && echo " Using VERBOSE mode."
420 [ -n "$PACK_ARTIFACTS" ] && echo " Will prepare packed artifacts and ensure clean build."
421 [ -n "$UPDATE" ] && echo " Executing UPDATE instead of fresh installation."
422 if [ -n "$BOOTSTRAP_ONLY" ] ; then
423 echo " Bootstrapping only and not building (files for) ISO."
425 [ -n "$SKIP_MKSQUASHFS" ] && echo " Skipping creation of SQUASHFS file."
426 [ -n "$SKIP_MKISOFS" ] && echo " Skipping creation of ISO file."
427 [ -n "$BUILD_ONLY" ] && echo " Executing BUILD_ONLY instead of fresh installation or UPDATE."
428 [ -n "$BUILD_DIRTY" ] && echo " Executing BUILD_DIRTY to leave chroot untouched."
431 echo -n "Is this ok for you? [y/N] "
433 if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
434 bailout 1 "Exiting as requested."
440 # clean up before start {{{
441 if [ -n "${PACK_ARTIFACTS}" ]; then
442 echo "Wiping old artifacts"
443 [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && rm -r "${CHROOT_OUTPUT}"
444 [ -n "${BUILD_OUTPUT}" -a -d "${BUILD_OUTPUT}" ] && rm -r "${BUILD_OUTPUT}"
445 [ -n "${ISO_OUTPUT}" -a -d "${ISO_OUTPUT}" ] && rm -r "${ISO_OUTPUT}"
446 [ -n "${LOG_OUTPUT}" -a -d "${LOG_OUTPUT}" ] && rm -r "${LOG_OUTPUT}"
447 [ -n "${CHROOT_ARCHIVE}" -a -f "${CHROOT_ARCHIVE}" ] && rm "${CHROOT_ARCHIVE}"
451 # create log file {{{
452 [ -n "$LOGFILE" ] || LOGFILE=${LOG_OUTPUT}/grml-live.log
453 mkdir -p $(dirname "${LOGFILE}")
455 chown root:adm $LOGFILE
459 # clean/zero/remove logfiles {{{
461 if [ -n "$PRESERVE_LOGFILE" ] ; then
462 echo "Preserving logfile $LOGFILE as requested via \$PRESERVE_LOGFILE"
464 # make sure it is empty (as it is e.g. appended to grml-live-db)
468 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
469 if [ -d /var/log/fai/"$HOSTNAME" ] ; then
470 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
471 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
472 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
473 rm -f /var/log/fai/"$HOSTNAME"/last \
474 /var/log/fai/"$HOSTNAME"/last-dirinstall \
475 /var/log/fai/"$HOSTNAME"/last-softupdate
480 # source config and startup {{{
481 if [ -n "$CONFIG" ] ; then
482 if ! [ -f "$CONFIG" ] ; then
483 log "Error: $CONFIG could not be read. Exiting. [$(date)]"
484 eerror "Error: $CONFIG could not be read. Exiting." ; eend 1
487 log "Sourcing $CONFIG"
492 start_seconds=$(cut -d . -f 1 /proc/uptime)
493 log "------------------------------------------------------------------------------"
494 log "Starting grml-live [${GRML_LIVE_VERSION}] run on $(date)"
495 if [ -n "$LOCAL_CONFIG" ]; then
496 log "Using local config file: $LOCAL_CONFIG"
498 log "Executed grml-live command line:"
501 einfo "Logging actions to logfile $LOGFILE"
504 # on-the-fly configuration {{{
505 if [ -n "$FAI_DEBOOTSTRAP" ] ; then
506 sed "s#^FAI_DEBOOTSTRAP=.*#FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"#" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
509 # does this suck? YES!
510 # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
512 unstable) SUITE='sid' ; CLASSES="DEBIAN_UNSTABLE,$CLASSES" ;;
513 *) CLASSES="DEBIAN_$(echo $SUITE | tr 'a-z' 'A-Z'),$CLASSES";;
515 export SUITE # make sure it's available in FAI scripts
517 for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" "$NFSROOT_CONF" ; do
518 if [ -n "$file" ] ; then
519 sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
523 # validate whether the specified architecture class matches the
524 # architecture (option), otherwise installation of kernel will fail
525 if echo $CLASSES | grep -qi i386 ; then
526 if ! [[ "$ARCH" == "i386" ]] ; then
527 log "Error: You specified the I386 class but are trying to build something else (AMD64?)."
528 eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
529 eerror "Tip: Either invoke grml-live with '-a i386' or adjust the architecture class. Exiting."
533 elif echo $CLASSES | grep -qi amd64 ; then
534 if ! [[ "$ARCH" == "amd64" ]] ; then
535 log "Error: You specified the AMD64 class but are trying to build something else (I386?)."
536 eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
537 eerror "Tip: Either invoke grml-live with '-a amd64' or adjust the architecture class. Exiting."
543 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
544 sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
546 sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
550 # CHROOT_OUTPUT - execute FAI {{{
551 if [ -n "$BUILD_DIRTY" ]; then
552 log "Skipping stage 'fai' as requested via option -B"
553 ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
555 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
557 # provide inform fai about the ISO we build
558 [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
559 echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
560 [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
561 [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
563 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
564 FAI_ACTION=softupdate
566 FAI_ACTION=dirinstall
569 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
570 if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
571 log "Error: does not look like you have a working chroot. Updating/building not possible."
572 eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
578 if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
579 log "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
580 ewarn "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
582 mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
584 if [ -n "${MIRROR_DIRECTORY}" ] ; then
585 mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
586 mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
589 mkdir -p "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
590 mount --bind "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
592 # tell dpkg to use "unsafe io" during the build
593 [ -d "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d" ] || mkdir -p "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d"
594 echo force-unsafe-io > "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
596 log "Executed FAI command line:"
597 log "BUILD_ONLY=$BUILD_ONLY BOOTSTRAP_ONLY=$BOOTSTRAP_ONLY fai $VERBOSE -C $GRML_FAI_CONFIG -s file:///$GRML_FAI_CONFIG/config -c$CLASSES -u $HOSTNAME $FAI_ACTION $CHROOT_OUTPUT $FAI_ARGS"
598 BUILD_ONLY="$BUILD_ONLY" BOOTSTRAP_ONLY="$BOOTSTRAP_ONLY" fai $VERBOSE \
599 -C "$GRML_FAI_CONFIG" -s "file:///$GRML_FAI_CONFIG/config" -c"$CLASSES" \
600 -u "$HOSTNAME" "$FAI_ACTION" "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
601 RC="$PIPESTATUS" # notice: bash-only
603 rm -f "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
605 FORCE_ISO_REBUILD=true
607 if [ "$RC" != 0 ] ; then
608 log "Error: critical error while executing fai [exit code ${RC}]. Exiting."
609 eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
612 einfo "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
613 log "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
614 echo "$GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]" > $CHROOT_OUTPUT/etc/grml_version
615 chmod 644 $CHROOT_OUTPUT/etc/grml_version
616 einfo "Rebuilding initramfs"
617 # make sure new /etc/grml_version reaches initramfs, iterate over all
618 # present kernel versions (note: we can't really handle more than one
619 # kernel version anyway right now)
620 # chroot $CHROOT_OUTPUT update-initramfs -u -t => might break when using kernel-package :(
621 for initrd in "$(basename $CHROOT_OUTPUT/boot/vmlinuz-*)" ; do
622 if ! chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -c ; then
623 einfo "Creating fresh initrd did not work, trying update instead:"
624 log "Creating fresh initrd did not work, trying update instead:"
625 chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -u
631 # move fai logs into grml_logs directory
632 mkdir -p "$LOG_OUTPUT"/fai/
633 cp -r "$CHROOT_OUTPUT"/var/log/fai/"$HOSTNAME"/last/* "$LOG_OUTPUT"/fai/
634 rm -rf "$CHROOT_OUTPUT"/var/log/fai
635 # copy fai package list
636 cp "$CHROOT_OUTPUT"/var/log/install_packages.list "$LOG_OUTPUT"/fai/
638 chown root:adm "$LOG_OUTPUT"/fai/*
639 chmod 664 "$LOG_OUTPUT"/fai/*
643 # notice: 'fai dirinstall' does not seem to exit appropriate, so:
645 CHECKLOG="$LOG_OUTPUT"/fai/
646 if [ -r "$CHECKLOG/software.log" ] ; then
647 # 1 errors during executing of commands
648 grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
649 grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
650 grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
651 grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
652 grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
655 if [ -r "$CHECKLOG/shell.log" ] ; then
656 grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=6
659 if [ -n "$ERROR" ] ; then
660 log "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
661 eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
662 eerror "Note: check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
666 log "Finished execution of stage 'fai dirinstall' [$(date)]"
667 einfo "Finished execution of stage 'fai dirinstall'"
673 # package validator {{{
674 CHECKLOG=/var/log/fai/$HOSTNAME/last
676 if [ -r "$CHECKLOG/package_errors.log" ] && grep -q '[a-z]' "$CHECKLOG/package_errors.log" ; then
678 if [ -n "$EXIT_ON_MISSING_PACKAGES" -a -z "$BUILD_DIRTY" ] ; then
679 eerror "The following packages were requested for installation but could not be processed:"
680 cat $CHECKLOG/package_errors.log
681 eerror "... exiting as requested via \$EXIT_ON_MISSING_PACKAGES."
685 ewarn "The following packages were requested for installation but could not be processed:"
686 cat $CHECKLOG/package_errors.log
692 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
693 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
694 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
697 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
698 if [ -n "$BOOTSTRAP_ONLY" ] ; then
699 log "Skipping stage 'boot' as building with bootstrap only."
700 ewarn "Skipping stage 'boot' as building with bootstrap only." ; eend 0
702 if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
703 log "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already."
704 ewarn "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already." ; eend 0
707 [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
708 [ -d "$BUILD_OUTPUT"/boot/"${SHORT_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
710 # if we don't have an initrd we a) can't boot and b) there was an error
711 # during build, so check for the file:
712 INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
713 if [ -n "$INITRD" ] ; then
714 cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.gz
715 find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
717 log "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
718 eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
722 KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
723 if [ -n "$KERNEL_IMAGE" ] ; then
724 cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/linux26
726 log "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
727 eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
731 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
732 if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
733 log "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
734 eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
738 # copy _required_ isolinux files
739 for file in ifcpu64.c32 isolinux.bin vesamenu.c32; do
740 copy_addon_file "${file}" /usr/lib/syslinux isolinux
743 # *always* copy files to output directory so the variables
744 # get adjusted according to the build.
745 cp ${TEMPLATE_DIRECTORY}/boot/isolinux/* "$BUILD_OUTPUT"/boot/isolinux/
747 if [ -n "$NO_ADDONS" ] ; then
748 log "Skipping installation of boot addons as requested via \$NO_ADDONS."
749 einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
751 if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
752 log "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
753 ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
755 # copy addons from system packages or grml-live-compat
756 copy_addon_file ipxe.lkrn /usr/lib/ipxe addons
757 copy_addon_file pci.ids /usr/share/misc addons
758 copy_addon_file memtest86+.bin /boot addons
759 for file in memdisk chain.c32 hdt.c32 menu.c32; do
760 copy_addon_file "${file}" /usr/lib/syslinux addons
763 # make memtest filename FAT16/8.3 compatible
764 mv "${BUILD_OUTPUT}/boot/addons/memtest86+.bin" \
765 "${BUILD_OUTPUT}/boot/addons/memtest"
767 # copy only files so we can handle bsd4grml on its own
768 for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
769 test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
772 if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
773 log "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
774 einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
776 if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
777 cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
779 log "Missing addon file: bsd4grml"
780 ewarn "Missing addon file: bsd4grml" ; eend 0
784 fi # no "$TEMPLATE_DIRECTORY"/boot/addons
787 if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
788 mkdir -p "${BUILD_OUTPUT}/boot/grub"
790 cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
792 if [ -e ${TEMPLATE_DIRECTORY}/compat/grub/linux.mod ]; then
793 cp "${TEMPLATE_DIRECTORY}"/compat/grub/* "${BUILD_OUTPUT}"/boot/grub/
795 if ! which "grub-mkimage" >/dev/null 2>&1 ; then
796 log "grub-mkimage not found, skipping Grub step therefore." ; eend 0
797 ewarn "grub-mkimage not found, skipping Grub step therefore."
798 ewarn "Please install grub-pc-bin or grub-common >= 1.98+20100804-14." ; eend 0
799 elif ! grub-mkimage --help | grep -q -- --format ; then
800 log "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore." ; eend 0
801 ewarn "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore."
802 ewarn "Please install grub-common >= 1.98+20100804-14 or grub-pc-bin." ; eend 0
804 # copy system grub files if grml-live-compat is not installed
805 cp -a /usr/lib/grub/*-pc/*.mod "${BUILD_OUTPUT}"/boot/grub/
806 cp -a /usr/lib/grub/*-pc/*.o "${BUILD_OUTPUT}"/boot/grub/
807 cp -a /usr/lib/grub/*-pc/*.lst "${BUILD_OUTPUT}"/boot/grub/
808 cp -a /usr/share/grub/ascii.pf2 "${BUILD_OUTPUT}"/boot/grub/
809 grub-mkimage -d /usr/lib/grub/*-pc -o \
810 "${BUILD_OUTPUT}/boot/grub/core.img" biosdisk iso9660 --format=i386-pc
814 if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
815 log "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
816 eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
820 [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
821 cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
823 # adjust boot splash information:
824 RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
825 RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
826 RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
828 if [ -r "$BUILD_OUTPUT"/GRML/grml-version ] ; then
829 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
830 sed -i "s/%DATE%/$DATE/" "$BUILD_OUTPUT"/GRML/grml-version
833 # make sure the squashfs filename is set accordingly:
834 SQUASHFS_NAME="$GRML_NAME.squashfs"
836 if [ -n "$NO_BOOTID" ] ; then
837 log 'Skipping bootid feature as requested via $NO_BOOTID.'
838 einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
840 [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
841 [ -d "$BUILD_OUTPUT"/conf ] || mkdir "$BUILD_OUTPUT"/conf
842 einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
843 log "Generating /conf/bootid.txt with entry ${BOOTID}."
844 echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
848 # adjust all variables in the templates with the according distribution information
849 for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
850 "${BUILD_OUTPUT}"/boot/grub/* ; do
851 if [ -r "${file}" ] ; then
852 sed -i "s/%ARCH%/$ARCH/g" "${file}"
853 sed -i "s/%DATE%/$DATE/g" "${file}"
854 sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g" "${file}"
855 sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g" "${file}"
856 sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g" "${file}"
857 sed -i "s/%GRML_NAME%/$GRML_NAME/g" "${file}"
858 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g" "${file}"
859 sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g" "${file}"
860 sed -i "s/%SHORT_NAME%/$SHORT_NAME/g" "${file}"
861 sed -i "s/%VERSION%/$VERSION/g" "${file}"
863 [ -n "$DEFAULT_BOOTOPTIONS" ] && sed -i "s/ boot=live/ boot=live $DEFAULT_BOOTOPTIONS/" "${file}"
865 if [ -n "$NO_BOOTID" ] ; then
866 sed -i "s/ bootid=%BOOTID%//g" "${file}" # drop bootid bootoption
868 sed -i "s/%BOOTID%/$BOOTID/g" "${file}" # adjust bootid=... argument
873 # adjust bootsplash accordingly but make sure the string has the according lenght
874 SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
875 SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
876 for file in f4 f5 ; do
877 if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
878 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
879 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
883 # generate addon list
884 rm -f "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
885 for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
886 include_name=$(basename "$name")
887 echo "include $include_name" >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
890 if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
891 log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
892 echo "include grmlmain.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
893 echo "include default.cfg" > "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
894 echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
895 echo "include grml.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
897 for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
898 echo "include $(basename $f)" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
901 echo "include options.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
902 if [ ! -n "$NO_ADDONS" ] ; then
903 echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
905 echo "include isoprompt.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
906 echo "include hd.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
907 echo "include hidden.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
908 else # assume we are building a custom distribution:
909 log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
910 einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
911 if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
912 log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
914 einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
918 log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
919 echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
920 [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
924 # use old style console based isolinux method only if requested:
925 if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
926 log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
927 einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
928 if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
929 einfo "include for console.cfg already found, nothing to do."
932 log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
933 einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
934 echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
938 log 'Using graphical boot menu.'
939 if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
940 log "include for vesamenu.cfg already found, nothing to do."
942 log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
943 echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
947 if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
948 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
951 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
952 if ! [ -r "$DPKG_LIST" ] ; then
953 ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
955 einfo "Storing package list information as /GRML/${GRML_NAME}-packages.txt on ISO."
956 cp "$DPKG_LIST" "${BUILD_OUTPUT}/GRML/${GRML_NAME}-packages.txt"
960 # autostart for Windows:
961 if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
962 cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
965 FORCE_ISO_REBUILD=true
966 einfo "Finished execution of stage 'boot'" ; eend 0
970 log 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
971 eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
975 # support installation of local files into the chroot/ISO
976 if [ -n "$CHROOT_INSTALL" ] ; then
977 if ! [ -d "$CHROOT_INSTALL" ] ; then
978 log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
979 ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
981 log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
982 einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
983 rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
985 einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
986 FORCE_ISO_REBUILD=true
990 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
991 log "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
992 ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
993 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
994 log "Skipping stage 'squashfs' as requested via option -q or -N"
995 ewarn "Skipping stage 'squashfs' as requested via option -q or -N" ; eend 0
997 [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
998 # make sure we don't leave (even an empty) base.tgz:
999 [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
1001 # if unconfigured default to squashfs-tools' mksquashfs binary
1002 if [ -z "$SQUASHFS_BINARY" ] ; then
1003 SQUASHFS_BINARY='mksquashfs'
1006 if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
1007 log "Using mksquashfs binary ${SQUASHFS_BINARY}"
1008 einfo "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
1010 log "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
1011 eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
1015 # use sane defaults if $SQUASHFS_OPTIONS isn't set
1016 if [ -z "$SQUASHFS_OPTIONS" ] ; then
1017 # use blocksize 256k as this gives best result with regards to time + compression
1018 SQUASHFS_OPTIONS="-b 256k"
1020 # set lzma/xz compression by default, unless -z option has been specified on command line
1021 if [ -z "$SQUASHFS_ZLIB" ] ; then
1022 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp xz"
1024 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp gzip"
1028 # support exclusion of files via exclude-file:
1029 if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
1030 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE -wildcards"
1033 # get rid of unnecessary files when building grml-small for final release:
1034 if echo "$CLASSES" | grep -q GRML_SMALL ; then
1035 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
1039 SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
1041 # informational stuff
1042 [ -n "$SQUASHFS_OPTIONS" ] && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
1043 [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
1044 einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
1046 log "$SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS"
1048 if $SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
1049 -noappend $SQUASHFS_OPTIONS 2>"${SQUASHFS_STDERR}" ; then
1050 echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
1051 log "Finished execution of stage 'squashfs' [$(date)]"
1052 einfo "Finished execution of stage 'squashfs'" ; eend 0
1054 log "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1055 log "$(cat $SQUASHFS_STDERR)"
1056 eerror "Error: there was a critical error executing stage 'squashfs':"
1057 cat "${SQUASHFS_STDERR}"
1062 FORCE_ISO_REBUILD=true
1065 # create md5sum file:
1066 if [ -z "$BOOTSTRAP_ONLY" ] ; then
1067 ( cd $BUILD_OUTPUT/GRML &&
1068 find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1072 # ISO_OUTPUT - mkisofs {{{
1073 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1074 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1076 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1077 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1078 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1079 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1082 # Just until http://bts.grml.org/grml/issue945 has been resolved.
1083 # HYBRID_METHOD defaults to manifold, so make sure the default works OOTB.
1084 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1085 log "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1086 ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1087 HYBRID_METHOD='grub2'
1091 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ] ; then
1092 log "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1093 ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1094 elif [ -n "$SKIP_MKISOFS" ] ; then
1095 log "Skipping stage 'iso build' as requested via option -n or -N"
1096 ewarn "Skipping stage 'iso build' as requested via option -n or -N" ; eend 0
1098 mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1100 if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1101 log "Forcing rebuild of ISO because files on ISO have been modified."
1102 einfo "Forcing rebuild of ISO because files on ISO have been modified."
1105 # support mkisofs as well as genisoimage
1106 if which mkisofs >/dev/null 2>&1; then
1108 elif which genisoimage >/dev/null 2>&1; then
1109 MKISOFS='genisoimage'
1111 log "Error: neither mkisofs nor genisoimage available - can not create ISO."
1112 eerror "Error: neither mkisofs nor genisoimage available - can not create ISO." ; eend 1
1117 if cd "$BUILD_OUTPUT" ; then
1118 if [ "$BOOT_METHOD" = "grub2" ]; then
1119 # make a 2048-byte bootsector for El Torito
1120 dd if=/dev/zero of=boot/grub/toriboot.bin bs=512 count=4 2>/dev/null
1121 # those are in 2048-byte sectors, so 1 16 matches 4 63 below
1122 echo 1 16 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -B 11 | \
1123 dd of=boot/grub/toriboot.bin conv=notrunc 2>/dev/null
1125 log "$MKISOFS -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J $BOOT_ARGS -o ${ISO_OUTPUT}/${ISO_NAME} ."
1126 "$MKISOFS" -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1127 -l -r -J $BOOT_ARGS -no-pad \
1128 -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1129 # both of these need core.img there, so it’s easier to write it here
1130 if [ "$BOOT_METHOD" = "grub2" ] || [ "$HYBRID_METHOD" = "grub2" ]; then
1131 # must be <= 30720 bytes
1132 dd if=boot/grub/core.img of="${ISO_OUTPUT}/${ISO_NAME}" \
1133 conv=notrunc bs=512 seek=4 2>/dev/null
1136 # pad the output ISO to multiples of 256 KiB for partition table support
1137 siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1138 cyls=$((siz / 512 / 32 / 16 + 1)) # C=$cyls H=16 S=32
1139 siz=$((cyls * 16 * 32 * 512)) # size after padding
1140 dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1141 of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1143 # support disabling hybrid ISO image
1144 if [ "$HYBRID_METHOD" = "disable" ] ; then\
1145 log "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1146 einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1148 # use isohybrid only on request
1149 elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
1150 if ! which isohybrid >/dev/null 2>&1 ; then
1151 bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1153 log "Creating hybrid ISO file with isohybrid method"
1154 einfo "Creating hybrid ISO file with isohybrid method"
1155 # Notes for consideration:
1156 # "-entry 4 -type 1c"
1157 # * using 4 as the partition number is supposed to help with BIOSes
1158 # that only support USB-Zip boot
1159 # * using 1c (i.e. hidden FAT32 LBA), instead of the default 0x17
1160 # (hidden NTFS, IIRC), as the partition type is sometimes needed
1161 # to get the BIOS even look at the partition created by isohybrid
1162 isohybrid "${ISO_OUTPUT}/${ISO_NAME}"
1165 # by default use our manifold boot method:
1167 # isoinfo is part of both mkisofs and genisoimage so we're good
1168 bootoff=$(isoinfo -l -i "${ISO_OUTPUT}/${ISO_NAME}" | \
1169 sed -n '/^.*\[ *\([0-9]*\)[] ].* ISOLINUX.BIN;1 *$/s//\1/p')
1170 if ! [ -r boot/grub/core.img ] ; then
1171 ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1172 elif [ "${bootoff:-0}" -lt 1 ] ; then
1173 ewarn "isolinux.bin not found on the ISO file, disabling manifold boot"
1175 log "Creating hybrid ISO file with manifold method"
1176 einfo "Creating hybrid ISO file with manifold method"
1177 if [ "$HYBRID_METHOD" = "grub2" ] ; then
1178 # 512 bytes: MBR, partition table, load GRUB 2
1179 echo 4 63 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 4:0x96 -g $cyls:16:32
1181 # read only one but 2048-byte sized (scale: << 2) sector
1182 echo $bootoff $bootoff | \
1183 mksh /usr/share/grml-live/scripts/bootilnx.mksh -A -M 4:0x96 -g $cyls:16:32 -S 2
1184 fi | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1189 # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1190 case $CLASSES in *RELEASE*)
1193 if cd $ISO_OUTPUT ; then
1194 md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1195 touch -r ${ISO_NAME} ${ISO_NAME}.md5
1196 sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1197 touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1206 if [ "$RC" = 0 ] ; then
1207 log "Finished execution of stage 'iso build' [$(date)]"
1208 einfo "Finished execution of stage 'iso build'" ; eend 0
1210 log "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1211 eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1217 # pack artifacts {{{
1218 if [ -n "$PACK_ARTIFACTS" ]; then
1219 log "Packing artifcats"
1220 einfo "Packing artifacts"
1221 [ -f "${CHROOT_ARCHIVE}" ] && rm -r "${CHROOT_ARCHIVE}"
1222 tar -c -a -f ${CHROOT_ARCHIVE} --preserve-permissions -C "$(dirname ${CHROOT_OUTPUT})" "$(basename ${CHROOT_OUTPUT})"
1227 # log build information to database if grml-live-db is installed and enabled {{{
1229 if [ -d /usr/share/grml-live-db ] ; then
1232 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1233 [ -n "$DPKG_DATABASE" ] || DPKG_DATABASE=/var/log/grml-live.db
1234 [ -n "$DPKG_DBSCRIPT" ] || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1235 [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1237 if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1238 log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1239 eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1243 # disable by default for now, not sure whether really everyone is using a local db file
1244 #if ! touch "$DPKG_DATABASE" ; then
1245 # eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1249 if ! [ -r "$DPKG_LIST" ] ; then
1250 log "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1251 ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1253 einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1254 log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1255 log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1258 if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1274 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1275 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1277 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1279 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1283 ## END OF FILE #################################################################
1284 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2