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 -T <tar_name> unpack chroot tar archive before starting
63 -u update existing chroot instead of rebuilding it from scratch
64 -U <username> arrange output to be owned by specified username
65 -v <version_number> specify version number of the release
66 -V increase verbosity in the build process
67 -z use ZLIB instead of LZMA/XZ compression
72 $PN -c GRMLBASE,GRML_FULL,AMD64 -o /dev/shm/grml
73 $PN -c GRMLBASE,GRML_FULL,AMD64 -i grml_0.0-1.iso -v 0.0-1
74 $PN -c GRMLBASE,GRML_FULL,AMD64 -s sid -V -r 'grml-live rocks'
76 More details: man grml-live + /usr/share/doc/grml-live/grml-live.html
77 http://grml.org/grml-live/
79 Please send your bug reports and feedback to the grml-team: http://grml.org/bugs/
83 # make sure it's possible to get usage information without being
84 # root or actually executing the script
85 if [ "$1" = '-h' -o "$1" = '--help' ] ; then
87 [ "$(id -u 2>/dev/null)" != 0 ] && echo "Please notice that this script requires root permissions."
92 # some runtime checks {{{
93 # we need root permissions for the build-process:
94 if [ "$(id -u 2>/dev/null)" != 0 ] ; then
95 echo "Error: please run this script with uid 0 (root)." >&2
99 if [ -r /var/run/fai/FAI_INSTALLATION_IN_PROGRESS ] ; then
100 echo "/usr/sbin/fai already running or was aborted before.">&2
101 echo "You may remove /var/run/fai/FAI_INSTALLATION_IN_PROGRESS and try again.">&2
106 if [ -r /var/run/fai/fai_softupdate_is_running ] ; then
107 echo "/usr/sbin/fai softupdate already running or was aborted before.">&2
108 echo "You may remove /var/run/fai/fai_softupdate_is_running and try again.">&2
113 # lsb-functions and configuration stuff {{{
114 # make sure they are not set by default
123 # don't use colors/escape sequences
124 if [ -r /lib/lsb/init-functions ] ; then
125 . /lib/lsb/init-functions
126 ! log_use_fancy_output && NOCOLORS=true
129 if [ -r /etc/grml/lsb-functions ] ; then
130 . /etc/grml/lsb-functions
132 einfo() { echo " [*] $*" ;}
133 eerror() { echo " [!] $*">&2 ;}
134 ewarn() { echo " [x] $*" ;}
136 eindent() { return 0 ;}
137 eoutdent() { return 0 ;}
140 # source main configuration file:
141 LIVE_CONF=/etc/grml/grml-live.conf
145 # umount all directories {{{
147 # make sure we don't leave any mounts - FAI doesn't remove them always
148 umount $CHROOT_OUTPUT/proc 2>/dev/null || /bin/true
149 umount $CHROOT_OUTPUT/sys 2>/dev/null || /bin/true
150 umount $CHROOT_OUTPUT/dev/pts 2>/dev/null || /bin/true
151 umount $CHROOT_OUTPUT/dev 2>/dev/null || /bin/true
153 # certain FAI versions sadly leave a ramdisk behind, so better safe than sorry
154 if [ -x /usr/lib/fai/mkramdisk ] ; then
155 /usr/lib/fai/mkramdisk -u "$(readlink -f ${CHROOT_OUTPUT}/var/lib/dpkg)" >/dev/null 2>&1 || /bin/true
158 umount "${CHROOT_OUTPUT}/grml-live/sources/" 2>/dev/null || /bin/true
159 [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
165 rm -f /var/run/fai/fai_softupdate_is_running \
166 /var/run/fai/FAI_INSTALLATION_IN_PROGRESS
167 [ -n "$SQUASHFS_STDERR" ] && rm -rf "$SQUASHFS_STDERR"
169 [ -n "$1" ] && EXIT="$1" || EXIT="1"
170 [ -n "$2" ] && eerror "$2">&2
171 if [ -n "$PACK_ARTIFACTS" ]; then
174 [ -n "${BUILD_OUTPUT}" -a -d "${BUILD_OUTPUT}" ] && rm -r "${BUILD_OUTPUT}"
175 [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && rm -r "${CHROOT_OUTPUT}"
178 if [ -n "$CHOWN_USER" ]; then
179 log "Setting ownership"
180 einfo "Setting ownership"
181 [ -n "${OUTPUT}" -a -d "${OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${OUTPUT}"
182 [ -n "${BUILD_OUTPUT}" -a -d "${BUILD_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${BUILD_OUTPUT}"
183 [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${CHROOT_OUTPUT}"
184 [ -n "${ISO_OUTPUT}" -a -d "${ISO_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${ISO_OUTPUT}"
185 [ -n "${LOG_OUTPUT}" -a -d "${LOG_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${LOG_OUTPUT}"
186 [ -n "${CHROOT_ARCHIVE}" -a -f "${CHROOT_ARCHIVE}" ] && chown -R "${CHOWN_USER}:" "${CHROOT_ARCHIVE}"
189 log "------------------------------------------------------------------------------"
192 trap bailout 1 2 3 3 6 9 14 15
196 # some important functions {{{
199 # usage: log "string to log"
200 log() { [ -n "$LOGFILE" ] && echo "$*" >> $LOGFILE ; }
202 # cut string at character number int = $1
203 # usage: cut_string 5 "1234567890" will output "12345"
205 [ -n "$2" ] || return 1
206 echo "$2" | head -c "$1"; echo -ne "\n"
209 # prepend int = $1 spaces before string = $2
210 # usage: extend_string_begin 5 "123" will output " 123"
211 extend_string_begin() {
212 [ -n "$2" ] || return 1
213 local COUNT="$(echo $2 | wc -c)"
214 local FILL="$(expr $COUNT - $1)"
215 while [ "$FILL" -gt 1 ] ; do
217 local FILL=$(expr $FILL - 1)
219 while [ "$FILL" -lt 1 ] ; do
221 local FILL=$(expr $FILL + 1)
223 echo "$2" | head -c "$1"; echo -ne "\n"
226 # append int = $1 spaces to string = $2
227 # usage: extend_string_begin 5 "123" will output "123 "
228 extend_string_end() {
229 [ -n "$2" ] || return 1
230 echo -n "$2" | head -c "$1"
231 local COUNT="$(echo $2 | wc -c)"
232 local FILL="$(expr $COUNT - $1)"
233 while [ "$FILL" -gt 1 ] ; do
235 local FILL=$(expr $FILL - 1)
237 while [ "$FILL" -lt 1 ] ; do
239 local FILL=$(expr $FILL + 1)
244 # Copy addonfile $1 from either
245 # * the chroot (via $2, the system path),
246 # * or from TEMPLATE_DIRECTORY/compat (if exists),
247 # * or from the host system (again, using $2),
248 # or warn about the missing file.
251 # * We assume that the chroot always has a "good" version of
252 # the file. Also it makes sources handling easier.
253 # * On unstable, we Recommend the Debian packages containing
254 # these files. The user can override them by putting his
255 # "better" version into the chroot.
256 # * On stable, the Debian packages are probably not available,
257 # or outdated, so we look in TEMPLATE_DIRECTORY/compat first, where
258 # our grml-live-compat package installs current file versions.
260 DEST="${BUILD_OUTPUT}/boot/$3"
261 if [ ! -d "${DEST}/" ]; then
264 if [ -e "$CHROOT_OUTPUT/$2/$1" ]; then
265 log "Copying $1 from chroot"
266 cp "$CHROOT_OUTPUT/$2/$1" "${DEST}/"
269 if [ -e "${TEMPLATE_DIRECTORY}/compat/$3/$1" ]; then
270 log "Copying $1 from grml-live-compat"
271 cp "${TEMPLATE_DIRECTORY}/compat/$3/$1" "${DEST}/"
274 if [ -e "$2/$1" ]; then
275 log "Copying $1 from system"
276 cp "$2/$1" "${DEST}/"
280 msg="Missing addon file: \"$1\""
281 ewarn "$msg" ; eend 1
282 log "copy_addon_file: $msg"
286 # read local (non-packaged) configuration {{{
287 LOCAL_CONFIG=/etc/grml/grml-live.local
288 if [ -r "$LOCAL_CONFIG" ] ; then
294 if [ -n "${GRML_LIVE_SOURCES:-}" ] ; then
295 eerror "Config variable \$GRML_LIVE_SOURCES is set. This variable has been deprecated."
296 ewarn "Please set up ${GRML_FAI_CONFIG}/config/files/etc/apt/sources.list.d/* instead."
301 # command line parsing {{{
302 while getopts "a:C:c:d:D:g:i:I:o:r:s:t:T:U:v:AbBFnNquVz" opt; do
305 A) PACK_ARTIFACTS=1 ;;
308 c) CLASSES="$OPTARG" ;;
309 C) CONFIG="$OPTARG" ;;
311 D) GRML_FAI_CONFIG="$OPTARG" ;;
312 g) GRML_NAME="$OPTARG" ;;
313 i) ISO_NAME="$OPTARG" ;;
314 I) CHROOT_INSTALL="$OPTARG" ;;
316 N) BOOTSTRAP_ONLY=1; SKIP_MKISOFS=1; SKIP_MKSQUASHFS=1 ;;
317 o) OUTPUT="$OPTARG" ;;
318 q) SKIP_MKSQUASHFS=1 ;;
319 r) RELEASENAME="$OPTARG" ;;
320 s) SUITE="$OPTARG" ;;
321 t) TEMPLATE_DIRECTORY="$OPTARG";;
322 T) UNPACK_CHROOT="$(readlink -f $OPTARG)" ;;
323 v) VERSION="$OPTARG" ;;
326 U) CHOWN_USER="$OPTARG" ;;
328 z) SQUASHFS_ZLIB=1 ;;
329 ?) echo "invalid option -$OPTARG" >&2; bailout 1 ;;
332 shift $(($OPTIND - 1)) # set ARGV to the first not parsed commandline parameter
335 # assume sane defaults (if not set already) {{{
336 [ -n "$ARCH" ] || ARCH="$(dpkg --print-architecture)"
337 [ -n "$BOOT_METHOD" ] || BOOT_METHOD='isolinux'
338 [ -n "$CLASSES" ] || CLASSES="GRMLBASE,GRML_FULL,$(echo ${ARCH} | tr 'a-z' 'A-Z')"
339 [ -n "$DATE" ] || DATE="$(date +%Y-%m-%d)"
340 [ -n "$DISTRI_INFO" ] || DISTRI_INFO='Grml - Live Linux for system administrators '
341 [ -n "$DISTRI_NAME" ] || DISTRI_NAME="grml"
342 [ -n "$DISTRI_SPLASH" ] || DISTRI_SPLASH='grml.png'
343 [ -n "$FORCE_ISO_REBUILD" ] || FORCE_ISO_REBUILD="false"
344 [ -n "$GRML_FAI_CONFIG" ] || GRML_FAI_CONFIG='/etc/grml/fai'
345 [ -n "$GRML_NAME" ] || GRML_NAME='grml'
346 [ -n "$HOSTNAME" ] || HOSTNAME='grml'
347 [ -n "$HYBRID_METHOD" ] || HYBRID_METHOD='manifold'
348 [ -n "$NFSROOT_CONF" ] || NFSROOT_CONF="${GRML_FAI_CONFIG}/make-fai-nfsroot.conf"
349 [ -n "$RELEASENAME" ] || RELEASENAME='grml-live rocks'
350 [ -n "$SQUASHFS_EXCLUDES_FILE" ] || SQUASHFS_EXCLUDES_FILE="${GRML_FAI_CONFIG}/config/grml/squashfs-excludes"
351 [ -n "$SUITE" ] || SUITE='squeeze'
352 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
353 [ -n "$USERNAME" ] || USERNAME='grml'
354 [ -n "$VERSION" ] || VERSION='0.0.1'
356 # output specific stuff, depends on $OUTPUT (iff not set):
357 [ -n "$OUTPUT" ] || OUTPUT='/grml/grml-live'
358 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
359 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
360 [ -n "$CHROOT_ARCHIVE" ] || CHROOT_ARCHIVE="$OUTPUT/$(basename $CHROOT_OUTPUT).tgz"
361 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
362 [ -n "$LOG_OUTPUT" ] || LOG_OUTPUT="$OUTPUT/grml_logs"
363 [ -n "$REPORTS" ] || REPORTS="${LOG_OUTPUT}/reports/"
366 # some misc checks before executing FAI {{{
367 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
368 specify it on the command line using the -c option."
369 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
370 specify it on the command line using the -o option."
372 # trim characters that are known to cause problems inside $GRML_NAME;
373 # for example isolinux does not like '-' inside the directory name
374 [ -n "$GRML_NAME" ] && export SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
376 # export variables to have them available in fai scripts:
377 [ -n "$GRML_NAME" ] && export GRML_NAME="$GRML_NAME"
378 [ -n "$RELEASENAME" ] && export RELEASENAME="$RELEASENAME"
381 # ZERO_LOGFILE - check for backwards compatibility reasons {{{
382 # this was default behaviour until grml-live 0.9.34:
383 if [ -n "$ZERO_LOGFILE" ] ; then
384 PRESERVE_LOGFILE='' # make sure it's cleaned then
385 ewarn "Please consider disabling the \$ZERO_LOGFILE option as grml-live clears..."
386 ewarn "... the logfile $LOGFILE by default (unless \$PRESERVE_LOGFILE is set) nowadays."
391 # ask user whether the setup is ok {{{
392 if [ -z "$FORCE" ] ; then
394 echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
396 echo " FAI classes: $CLASSES"
397 [ -r "$LOCAL_CONFIG" ] && echo " Local config: /etc/grml/grml-live.local"
398 [ -n "$CONFIG" ] && echo " Configuration: $CONFIG"
399 [ -n "$GRML_FAI_CONFIG" ] && echo " Config directory: $GRML_FAI_CONFIG"
400 echo " main directory: $OUTPUT"
401 [ -n "$UNPACK_CHROOT" ] && echo " Chroot from: $UNPACK_CHROOT"
402 [ -n "$CHROOT_OUTPUT" ] && echo " Chroot target: $CHROOT_OUTPUT"
403 [ -n "$BUILD_OUTPUT" ] && echo " Build target: $BUILD_OUTPUT"
404 [ -n "$ISO_OUTPUT" ] && echo " ISO target: $ISO_OUTPUT"
405 [ -n "$GRML_NAME" ] && echo " Grml name: $GRML_NAME"
406 [ -n "$RELEASENAME" ] && echo " Release name: $RELEASENAME"
407 [ -n "$DATE" ] && echo " Build date: $DATE"
408 [ -n "$VERSION" ] && echo " Grml version: $VERSION"
409 [ -n "$SUITE" ] && echo " Debian suite: $SUITE"
410 [ -n "$ARCH" ] && echo " Architecture: $ARCH"
411 [ -n "$BOOT_METHOD" ] && echo " Boot method: $BOOT_METHOD"
412 [ -n "$HYBRID_METHOD" ] && echo " Hybrid method: $HYBRID_METHOD"
413 [ -n "$TEMPLATE_DIRECTORY" ] && echo " Template files: $TEMPLATE_DIRECTORY"
414 [ -n "$CHROOT_INSTALL" ] && echo " Install files from directory to chroot: $CHROOT_INSTALL"
415 [ -n "$BOOTID" ] && echo " Boot identifier: $BOOTID"
416 [ -n "$NO_BOOTID" ] && echo " Skipping bootid feature."
417 [ -n "$CHOWN_USER" ] && echo " Output owner: $CHOWN_USER"
418 [ -n "$DEFAULT_BOOTOPTIONS" ] && echo " Adding default bootoptions: \"$DEFAULT_BOOTOPTIONS\""
419 [ -n "$FAI_ARGS" ] && echo " Additional arguments for FAI: $FAI_ARGS"
420 [ -n "$LOGFILE" ] && echo " Logging to file: $LOGFILE"
421 [ -n "$SQUASHFS_ZLIB" ] && echo " Using ZLIB (instead of LZMA/XZ) compression."
422 [ -n "$SQUASHFS_OPTIONS" ] && echo " Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
423 [ -n "$VERBOSE" ] && echo " Using VERBOSE mode."
424 [ -n "$PACK_ARTIFACTS" ] && echo " Will prepare packed artifacts and ensure clean build."
425 [ -n "$UPDATE" ] && echo " Executing UPDATE instead of fresh installation."
426 if [ -n "$BOOTSTRAP_ONLY" ] ; then
427 echo " Bootstrapping only and not building (files for) ISO."
429 [ -n "$SKIP_MKSQUASHFS" ] && echo " Skipping creation of SQUASHFS file."
430 [ -n "$SKIP_MKISOFS" ] && echo " Skipping creation of ISO file."
431 [ -n "$BUILD_ONLY" ] && echo " Executing BUILD_ONLY instead of fresh installation or UPDATE."
432 [ -n "$BUILD_DIRTY" ] && echo " Executing BUILD_DIRTY to leave chroot untouched."
435 echo -n "Is this ok for you? [y/N] "
437 if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
438 bailout 1 "Exiting as requested."
444 # clean up before start {{{
445 if [ -n "${PACK_ARTIFACTS}" ]; then
446 echo "Wiping old artifacts"
447 [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && rm -r "${CHROOT_OUTPUT}"
448 [ -n "${BUILD_OUTPUT}" -a -d "${BUILD_OUTPUT}" ] && rm -r "${BUILD_OUTPUT}"
449 [ -n "${ISO_OUTPUT}" -a -d "${ISO_OUTPUT}" ] && rm -r "${ISO_OUTPUT}"
450 [ -n "${LOG_OUTPUT}" -a -d "${LOG_OUTPUT}" ] && rm -r "${LOG_OUTPUT}"
454 # create log file {{{
455 [ -n "$LOGFILE" ] || LOGFILE=${LOG_OUTPUT}/grml-live.log
456 mkdir -p $(dirname "${LOGFILE}")
458 chown root:adm $LOGFILE
462 # clean/zero/remove logfiles {{{
464 if [ -n "$PRESERVE_LOGFILE" ] ; then
465 echo "Preserving logfile $LOGFILE as requested via \$PRESERVE_LOGFILE"
467 # make sure it is empty (as it is e.g. appended to grml-live-db)
471 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
472 if [ -d /var/log/fai/"$HOSTNAME" ] ; then
473 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
474 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
475 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
476 rm -f /var/log/fai/"$HOSTNAME"/last \
477 /var/log/fai/"$HOSTNAME"/last-dirinstall \
478 /var/log/fai/"$HOSTNAME"/last-softupdate
483 # source config and startup {{{
484 if [ -n "$CONFIG" ] ; then
485 if ! [ -f "$CONFIG" ] ; then
486 log "Error: $CONFIG could not be read. Exiting. [$(date)]"
487 eerror "Error: $CONFIG could not be read. Exiting." ; eend 1
490 log "Sourcing $CONFIG"
495 start_seconds=$(cut -d . -f 1 /proc/uptime)
496 log "------------------------------------------------------------------------------"
497 log "Starting grml-live [${GRML_LIVE_VERSION}] run on $(date)"
498 if [ -n "$LOCAL_CONFIG" ]; then
499 log "Using local config file: $LOCAL_CONFIG"
501 log "Executed grml-live command line:"
504 einfo "Logging actions to logfile $LOGFILE"
508 if [ -n "${UNPACK_CHROOT}" ]; then
509 log "Unpacking chroot from ${UNPACK_CHROOT}"
510 einfo "Unpacking chroot from ${UNPACK_CHROOT}"
511 [ -d "$CHROOT_OUTPUT" ] || mkdir -p "${CHROOT_OUTPUT}"
512 tar -xf "${UNPACK_CHROOT}" -C "${CHROOT_OUTPUT}/" --strip-components 1 | RC=$?
514 if [ "$RC" != 0 ] ; then
522 # cleanup CHROOT_ARCHIVE now {{{
523 if [ -n "${PACK_ARTIFACTS}" ]; then
524 # can't do this earlier, as UNPACK_CHROOT might point to CHROOT_ARCHIVE
525 [ -n "${CHROOT_ARCHIVE}" -a -f "${CHROOT_ARCHIVE}" ] && rm "${CHROOT_ARCHIVE}"
529 # on-the-fly configuration {{{
530 if [ -n "$FAI_DEBOOTSTRAP" ] ; then
531 sed "s#^FAI_DEBOOTSTRAP=.*#FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"#" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
534 # does this suck? YES!
535 # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
537 unstable) SUITE='sid' ; CLASSES="DEBIAN_UNSTABLE,$CLASSES" ;;
538 *) CLASSES="DEBIAN_$(echo $SUITE | tr 'a-z' 'A-Z'),$CLASSES";;
540 export SUITE # make sure it's available in FAI scripts
542 for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" "$NFSROOT_CONF" ; do
543 if [ -n "$file" ] ; then
544 sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
548 # validate whether the specified architecture class matches the
549 # architecture (option), otherwise installation of kernel will fail
550 if echo $CLASSES | grep -qi i386 ; then
551 if ! [[ "$ARCH" == "i386" ]] ; then
552 log "Error: You specified the I386 class but are trying to build something else (AMD64?)."
553 eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
554 eerror "Tip: Either invoke grml-live with '-a i386' or adjust the architecture class. Exiting."
558 elif echo $CLASSES | grep -qi amd64 ; then
559 if ! [[ "$ARCH" == "amd64" ]] ; then
560 log "Error: You specified the AMD64 class but are trying to build something else (I386?)."
561 eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
562 eerror "Tip: Either invoke grml-live with '-a amd64' or adjust the architecture class. Exiting."
568 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
569 sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
571 sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
575 # CHROOT_OUTPUT - execute FAI {{{
576 if [ -n "$BUILD_DIRTY" ]; then
577 log "Skipping stage 'fai' as requested via option -B"
578 ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
580 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
582 # provide inform fai about the ISO we build
583 [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
584 echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
585 [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
586 [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
588 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
589 FAI_ACTION=softupdate
591 FAI_ACTION=dirinstall
594 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
595 if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
596 log "Error: does not look like you have a working chroot. Updating/building not possible."
597 eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
603 if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
604 log "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
605 ewarn "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
607 mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
609 if [ -n "${MIRROR_DIRECTORY}" ] ; then
610 mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
611 mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
614 mkdir -p "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
615 mount --bind "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
617 # tell dpkg to use "unsafe io" during the build
618 [ -d "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d" ] || mkdir -p "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d"
619 echo force-unsafe-io > "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
621 log "Executed FAI command line:"
622 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"
623 BUILD_ONLY="$BUILD_ONLY" BOOTSTRAP_ONLY="$BOOTSTRAP_ONLY" fai $VERBOSE \
624 -C "$GRML_FAI_CONFIG" -s "file:///$GRML_FAI_CONFIG/config" -c"$CLASSES" \
625 -u "$HOSTNAME" "$FAI_ACTION" "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
626 RC="$PIPESTATUS" # notice: bash-only
628 rm -f "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
630 FORCE_ISO_REBUILD=true
632 if [ "$RC" != 0 ] ; then
633 log "Error: critical error while executing fai [exit code ${RC}]. Exiting."
634 eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
637 einfo "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
638 log "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
639 echo "$GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]" > $CHROOT_OUTPUT/etc/grml_version
640 chmod 644 $CHROOT_OUTPUT/etc/grml_version
641 einfo "Rebuilding initramfs"
642 # make sure new /etc/grml_version reaches initramfs, iterate over all
643 # present kernel versions (note: we can't really handle more than one
644 # kernel version anyway right now)
645 # chroot $CHROOT_OUTPUT update-initramfs -u -t => might break when using kernel-package :(
646 for initrd in "$(basename $CHROOT_OUTPUT/boot/vmlinuz-*)" ; do
647 if ! chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -c ; then
648 einfo "Creating fresh initrd did not work, trying update instead:"
649 log "Creating fresh initrd did not work, trying update instead:"
650 chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -u
656 # move fai logs into grml_logs directory
657 mkdir -p "$LOG_OUTPUT"/fai/
658 cp -r "$CHROOT_OUTPUT"/var/log/fai/"$HOSTNAME"/last/* "$LOG_OUTPUT"/fai/
659 rm -rf "$CHROOT_OUTPUT"/var/log/fai
660 # copy fai package list
661 cp "$CHROOT_OUTPUT"/var/log/install_packages.list "$LOG_OUTPUT"/fai/
663 chown root:adm "$LOG_OUTPUT"/fai/*
664 chmod 664 "$LOG_OUTPUT"/fai/*
668 # notice: 'fai dirinstall' does not seem to exit appropriate, so:
670 CHECKLOG="$LOG_OUTPUT"/fai/
671 if [ -r "$CHECKLOG/software.log" ] ; then
672 # 1 errors during executing of commands
673 grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
674 grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
675 grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
676 grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
677 grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
680 if [ -r "$CHECKLOG/shell.log" ] ; then
681 grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=6
684 if [ -n "$ERROR" ] ; then
685 log "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
686 eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
687 eerror "Note: check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
691 log "Finished execution of stage 'fai dirinstall' [$(date)]"
692 einfo "Finished execution of stage 'fai dirinstall'"
698 # package validator {{{
699 CHECKLOG=/var/log/fai/$HOSTNAME/last
700 if [ -r "$CHECKLOG/dpkg.selections" ] ; then
701 package_count=$(wc -l "$CHECKLOG/dpkg.selections" | awk '{print $1}')
703 package_count="unknown"
707 REPORT_MISSING_PACKAGES="${REPORTS}/TEST-MissingPackages.xml"
709 # check for missing packages
710 if ! [ -s "$CHECKLOG/package_errors.log" ] ; then
711 einfo "No missing packages found, generating empty junit report."
713 cat > "${REPORT_MISSING_PACKAGES}" << EOF
714 <?xml version="1.0" encoding="UTF-8"?>
715 <testsuite name="grml-live-missing-packages" tests="${package_count}" time="1" failures="0" errors="0" skipped="0" assertions="0">
716 <testcase name="test_missing_packages" time="0" assertions="0">
726 einfo "Missing packages found, generating junit report."
728 if [ -r "$CHECKLOG/package_errors.log" ] ; then
729 package_errors=$(wc -l "$CHECKLOG/package_errors.log" | awk '{print $1}')
731 package_errors="unknown"
735 REPORT_MISSING_PACKAGES="${REPORTS}/TEST-MissingPackages.xml"
737 cat > "${REPORT_MISSING_PACKAGES}" << EOF
738 <?xml version="1.0" encoding="UTF-8"?>
739 <testsuite name="grml-live-missing-packages" tests="${package_count}" time="1" failures="${package_errors}" errors="${package_errors}" skipped="0" assertions="0">
742 for package in $(awk '{print $5}' "${CHECKLOG}/package_errors.log" | sed 's/\.$//') ; do
743 cat >> "${REPORT_MISSING_PACKAGES}" << EOF
744 <testcase name="test_missing_packages_${package}" time="0" assertions="0">
745 <failure type="RuntimeError" message="Package ${package} is missing">
746 Package $package is missing in chroot
752 cat >> "${REPORT_MISSING_PACKAGES}" << EOF
761 if [ -n "$EXIT_ON_MISSING_PACKAGES" -a -z "$BUILD_DIRTY" ] ; then
762 eerror "The following packages were requested for installation but could not be processed:"
763 cat "$CHECKLOG/package_errors.log"
764 eerror "... exiting as requested via \$EXIT_ON_MISSING_PACKAGES."
768 ewarn "The following packages were requested for installation but could not be processed:"
769 cat "$CHECKLOG/package_errors.log"
775 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
776 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
777 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
780 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
781 if [ -n "$BOOTSTRAP_ONLY" ] ; then
782 log "Skipping stage 'boot' as building with bootstrap only."
783 ewarn "Skipping stage 'boot' as building with bootstrap only." ; eend 0
785 if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
786 log "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already."
787 ewarn "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already." ; eend 0
790 [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
791 [ -d "$BUILD_OUTPUT"/boot/"${SHORT_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
793 # if we don't have an initrd we a) can't boot and b) there was an error
794 # during build, so check for the file:
795 INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
796 if [ -n "$INITRD" ] ; then
797 cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.gz
798 find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
800 log "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
801 eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
805 KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
806 if [ -n "$KERNEL_IMAGE" ] ; then
807 cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/linux26
809 log "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
810 eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
814 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
815 if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
816 log "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
817 eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
821 # copy _required_ isolinux files
822 for file in ifcpu64.c32 isolinux.bin vesamenu.c32; do
823 copy_addon_file "${file}" /usr/lib/syslinux isolinux
826 # *always* copy files to output directory so the variables
827 # get adjusted according to the build.
828 cp ${TEMPLATE_DIRECTORY}/boot/isolinux/* "$BUILD_OUTPUT"/boot/isolinux/
830 if [ -n "$NO_ADDONS" ] ; then
831 log "Skipping installation of boot addons as requested via \$NO_ADDONS."
832 einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
834 if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
835 log "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
836 ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
838 # copy addons from system packages or grml-live-compat
839 copy_addon_file ipxe.lkrn /usr/lib/ipxe addons
840 copy_addon_file pci.ids /usr/share/misc addons
841 copy_addon_file memtest86+.bin /boot addons
842 for file in memdisk chain.c32 hdt.c32 menu.c32; do
843 copy_addon_file "${file}" /usr/lib/syslinux addons
846 # make memtest filename FAT16/8.3 compatible
847 mv "${BUILD_OUTPUT}/boot/addons/memtest86+.bin" \
848 "${BUILD_OUTPUT}/boot/addons/memtest"
850 # copy only files so we can handle bsd4grml on its own
851 for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
852 test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
855 if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
856 log "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
857 einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
859 if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
860 cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
862 log "Missing addon file: bsd4grml"
863 ewarn "Missing addon file: bsd4grml" ; eend 0
867 fi # no "$TEMPLATE_DIRECTORY"/boot/addons
870 if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
871 mkdir -p "${BUILD_OUTPUT}/boot/grub"
873 cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
875 if [ -e ${TEMPLATE_DIRECTORY}/compat/grub/linux.mod ]; then
876 cp "${TEMPLATE_DIRECTORY}"/compat/grub/* "${BUILD_OUTPUT}"/boot/grub/
878 if ! which "grub-mkimage" >/dev/null 2>&1 ; then
879 log "grub-mkimage not found, skipping Grub step therefore." ; eend 0
880 ewarn "grub-mkimage not found, skipping Grub step therefore."
881 ewarn "Please install grub-pc-bin or grub-common >= 1.98+20100804-14." ; eend 0
882 elif ! grub-mkimage --help | grep -q -- --format ; then
883 log "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore." ; eend 0
884 ewarn "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore."
885 ewarn "Please install grub-common >= 1.98+20100804-14 or grub-pc-bin." ; eend 0
887 # copy system grub files if grml-live-compat is not installed
888 cp -a /usr/lib/grub/*-pc/*.mod "${BUILD_OUTPUT}"/boot/grub/
889 cp -a /usr/lib/grub/*-pc/*.o "${BUILD_OUTPUT}"/boot/grub/
890 cp -a /usr/lib/grub/*-pc/*.lst "${BUILD_OUTPUT}"/boot/grub/
891 cp -a /usr/share/grub/ascii.pf2 "${BUILD_OUTPUT}"/boot/grub/
892 grub-mkimage -d /usr/lib/grub/*-pc -o \
893 "${BUILD_OUTPUT}/boot/grub/core.img" biosdisk iso9660 --format=i386-pc
897 if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
898 log "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
899 eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
903 [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
904 cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
906 # adjust boot splash information:
907 RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
908 RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
909 RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
911 if [ -r "$BUILD_OUTPUT"/GRML/grml-version ] ; then
912 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
913 sed -i "s/%DATE%/$DATE/" "$BUILD_OUTPUT"/GRML/grml-version
916 # make sure the squashfs filename is set accordingly:
917 SQUASHFS_NAME="$GRML_NAME.squashfs"
919 if [ -n "$NO_BOOTID" ] ; then
920 log 'Skipping bootid feature as requested via $NO_BOOTID.'
921 einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
923 [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
924 [ -d "$BUILD_OUTPUT"/conf ] || mkdir "$BUILD_OUTPUT"/conf
925 einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
926 log "Generating /conf/bootid.txt with entry ${BOOTID}."
927 echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
931 # adjust all variables in the templates with the according distribution information
932 for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
933 "${BUILD_OUTPUT}"/boot/grub/* ; do
934 if [ -r "${file}" ] ; then
935 sed -i "s/%ARCH%/$ARCH/g" "${file}"
936 sed -i "s/%DATE%/$DATE/g" "${file}"
937 sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g" "${file}"
938 sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g" "${file}"
939 sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g" "${file}"
940 sed -i "s/%GRML_NAME%/$GRML_NAME/g" "${file}"
941 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g" "${file}"
942 sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g" "${file}"
943 sed -i "s/%SHORT_NAME%/$SHORT_NAME/g" "${file}"
944 sed -i "s/%VERSION%/$VERSION/g" "${file}"
946 [ -n "$DEFAULT_BOOTOPTIONS" ] && sed -i "s/ boot=live/ boot=live $DEFAULT_BOOTOPTIONS/" "${file}"
948 if [ -n "$NO_BOOTID" ] ; then
949 sed -i "s/ bootid=%BOOTID%//g" "${file}" # drop bootid bootoption
951 sed -i "s/%BOOTID%/$BOOTID/g" "${file}" # adjust bootid=... argument
956 # adjust bootsplash accordingly but make sure the string has the according lenght
957 SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
958 SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
959 for file in f4 f5 ; do
960 if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
961 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
962 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
966 # generate addon list
967 rm -f "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
968 for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
969 include_name=$(basename "$name")
970 echo "include $include_name" >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
973 if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
974 log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
975 echo "include grmlmain.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
976 echo "include default.cfg" > "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
977 echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
978 echo "include grml.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
980 for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
981 echo "include $(basename $f)" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
984 echo "include options.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
985 if [ ! -n "$NO_ADDONS" ] ; then
986 echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
988 echo "include isoprompt.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
989 echo "include hd.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
990 echo "include hidden.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
991 else # assume we are building a custom distribution:
992 log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
993 einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
994 if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
995 log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
997 einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
1001 log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1002 echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1003 [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1007 # use old style console based isolinux method only if requested:
1008 if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
1009 log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
1010 einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
1011 if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
1012 einfo "include for console.cfg already found, nothing to do."
1015 log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1016 einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1017 echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1021 log 'Using graphical boot menu.'
1022 if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
1023 log "include for vesamenu.cfg already found, nothing to do."
1025 log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1026 echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1030 if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
1031 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
1034 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
1035 if ! [ -r "$DPKG_LIST" ] ; then
1036 ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
1038 einfo "Storing package list information as /GRML/${GRML_NAME}-packages.txt on ISO."
1039 cp "$DPKG_LIST" "${BUILD_OUTPUT}/GRML/${GRML_NAME}-packages.txt"
1043 # autostart for Windows:
1044 if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
1045 cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
1048 FORCE_ISO_REBUILD=true
1049 einfo "Finished execution of stage 'boot'" ; eend 0
1053 log 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
1054 eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
1058 # support installation of local files into the chroot/ISO
1059 if [ -n "$CHROOT_INSTALL" ] ; then
1060 if ! [ -d "$CHROOT_INSTALL" ] ; then
1061 log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1062 ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1064 log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1065 einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1066 rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
1068 einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
1069 FORCE_ISO_REBUILD=true
1073 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
1074 log "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
1075 ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
1076 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
1077 log "Skipping stage 'squashfs' as requested via option -q or -N"
1078 ewarn "Skipping stage 'squashfs' as requested via option -q or -N" ; eend 0
1080 [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
1081 # make sure we don't leave (even an empty) base.tgz:
1082 [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
1084 # if unconfigured default to squashfs-tools' mksquashfs binary
1085 if [ -z "$SQUASHFS_BINARY" ] ; then
1086 SQUASHFS_BINARY='mksquashfs'
1089 if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
1090 log "Using mksquashfs binary ${SQUASHFS_BINARY}"
1091 einfo "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
1093 log "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
1094 eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
1098 # use sane defaults if $SQUASHFS_OPTIONS isn't set
1099 if [ -z "$SQUASHFS_OPTIONS" ] ; then
1100 # use blocksize 256k as this gives best result with regards to time + compression
1101 SQUASHFS_OPTIONS="-b 256k"
1103 # set lzma/xz compression by default, unless -z option has been specified on command line
1104 if [ -z "$SQUASHFS_ZLIB" ] ; then
1105 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp xz"
1107 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp gzip"
1111 # support exclusion of files via exclude-file:
1112 if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
1113 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE -wildcards"
1116 # get rid of unnecessary files when building grml-small for final release:
1117 if echo "$CLASSES" | grep -q GRML_SMALL ; then
1118 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
1122 SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
1124 # informational stuff
1125 [ -n "$SQUASHFS_OPTIONS" ] && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
1126 [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
1127 einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
1129 log "$SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS"
1131 if $SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
1132 -noappend $SQUASHFS_OPTIONS 2>"${SQUASHFS_STDERR}" ; then
1133 echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
1134 log "Finished execution of stage 'squashfs' [$(date)]"
1135 einfo "Finished execution of stage 'squashfs'" ; eend 0
1137 log "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1138 log "$(cat $SQUASHFS_STDERR)"
1139 eerror "Error: there was a critical error executing stage 'squashfs':"
1140 cat "${SQUASHFS_STDERR}"
1145 FORCE_ISO_REBUILD=true
1148 # create md5sum file:
1149 if [ -z "$BOOTSTRAP_ONLY" ] ; then
1150 ( cd $BUILD_OUTPUT/GRML &&
1151 find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1155 # ISO_OUTPUT - mkisofs {{{
1156 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1157 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1159 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1160 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1161 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1162 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1165 # Just until http://bts.grml.org/grml/issue945 has been resolved.
1166 # HYBRID_METHOD defaults to manifold, so make sure the default works OOTB.
1167 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1168 log "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1169 ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1170 HYBRID_METHOD='grub2'
1174 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ] ; then
1175 log "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1176 ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1177 elif [ -n "$SKIP_MKISOFS" ] ; then
1178 log "Skipping stage 'iso build' as requested via option -n or -N"
1179 ewarn "Skipping stage 'iso build' as requested via option -n or -N" ; eend 0
1181 mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1183 if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1184 log "Forcing rebuild of ISO because files on ISO have been modified."
1185 einfo "Forcing rebuild of ISO because files on ISO have been modified."
1188 # support xorriso as well mkisofs and genisoimage
1189 if which xorriso >/dev/null 2>&1 && \
1190 dpkg --compare-versions $(dpkg-query -W -f='${Version}\n' xorriso 2>/dev/null) gt-nl 1.1.6-2 ; then
1191 MKISOFS='xorriso -as mkisofs'
1192 elif which mkisofs >/dev/null 2>&1; then
1194 elif which genisoimage >/dev/null 2>&1; then
1195 MKISOFS='genisoimage'
1197 log "Error: neither xorriso nor mkisofs nor genisoimage available - can not create ISO."
1198 eerror "Error: neither xorriso nor mkisofs nor genisoimage available - can not create ISO." ; eend 1
1204 # using -eltorito-alt-boot is limited to xorriso for now
1207 einfo "Using xorriso for ISO generation." ; eend 0
1209 if [ -r "${CHROOT_OUTPUT}/var/lib/grml_live_efi.img" ] ; then
1210 einfo "Found /var/lib/grml_live_efi.img - moving to /boot/efi.img for ISO."
1211 log "Found /var/lib/grml_live_efi.img - moving to /boot/efi.img for ISO."
1212 mv "${CHROOT_OUTPUT}/var/lib/grml_live_efi.img" "${BUILD_OUTPUT}/boot/efi.img"
1216 if [ -r "${CHROOT_OUTPUT}/var/lib/grml_live_bootx64.efi" ] ; then
1217 einfo "Found /var/lib/grml_live_bootx64.efi - moving to /efi/boot/bootx64.efi for ISO"
1218 log "Found /var/lib/grml_live_bootx64.efi - moving to /efi/boot/bootx64.efi for ISO"
1219 mkdir -p "${BUILD_OUTPUT}/efi/boot/"
1220 mv "${CHROOT_OUTPUT}/var/lib/grml_live_bootx64.efi" "${BUILD_OUTPUT}/efi/boot/bootx64.efi"
1224 if [ -r "${BUILD_OUTPUT}"/boot/efi.img ] ; then
1225 einfo "/boot/efi.img found and amd64 architecture present, extending boot arguments."
1226 log "/boot/efi.img found and amd64 architecture present, extending boot arguments."
1227 BOOT_ARGS="$BOOT_ARGS -boot-info-table -eltorito-alt-boot -e boot/efi.img -no-emul-boot"
1236 if cd "$BUILD_OUTPUT" ; then
1237 if [ "$BOOT_METHOD" = "grub2" ]; then
1238 # make a 2048-byte bootsector for El Torito
1239 dd if=/dev/zero of=boot/grub/toriboot.bin bs=512 count=4 2>/dev/null
1240 # those are in 2048-byte sectors, so 1 16 matches 4 63 below
1241 echo 1 16 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -B 11 | \
1242 dd of=boot/grub/toriboot.bin conv=notrunc 2>/dev/null
1244 log "$MKISOFS -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J $BOOT_ARGS -o ${ISO_OUTPUT}/${ISO_NAME} ."
1245 $MKISOFS -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1246 -l -r -J $BOOT_ARGS -no-pad \
1247 -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1248 # both of these need core.img there, so it’s easier to write it here
1249 if [ "$BOOT_METHOD" = "grub2" ] || [ "$HYBRID_METHOD" = "grub2" ]; then
1250 # must be <= 30720 bytes
1251 dd if=boot/grub/core.img of="${ISO_OUTPUT}/${ISO_NAME}" \
1252 conv=notrunc bs=512 seek=4 2>/dev/null
1255 # pad the output ISO to multiples of 256 KiB for partition table support
1256 siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1257 cyls=$((siz / 512 / 32 / 16 + 1)) # C=$cyls H=16 S=32
1258 siz=$((cyls * 16 * 32 * 512)) # size after padding
1259 dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1260 of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1262 # support disabling hybrid ISO image
1263 if [ "$HYBRID_METHOD" = "disable" ] ; then\
1264 log "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1265 einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1267 elif [ "$HYBRID_METHOD" = "manifold" ] ; then
1268 # isoinfo is part of both mkisofs and genisoimage so we're good
1269 bootoff=$(isoinfo -l -i "${ISO_OUTPUT}/${ISO_NAME}" | \
1270 sed -n '/^.*\[ *\([0-9]*\)[] ].* ISOLINUX.BIN[;1]* *$/s//\1/p')
1271 if ! [ -r boot/grub/core.img ] ; then
1272 ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1273 elif [ "${bootoff:-0}" -lt 1 ] ; then
1274 ewarn "isolinux.bin not found on the ISO file, disabling manifold boot"
1276 log "Creating hybrid ISO file with manifold method"
1277 einfo "Creating hybrid ISO file with manifold method"
1278 if [ "$HYBRID_METHOD" = "grub2" ] ; then
1279 # 512 bytes: MBR, partition table, load GRUB 2
1280 echo 4 63 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 4:0x96 -g $cyls:16:32
1282 # read only one but 2048-byte sized (scale: << 2) sector
1283 echo $bootoff $bootoff | \
1284 mksh /usr/share/grml-live/scripts/bootilnx.mksh -A -M 4:0x96 -g $cyls:16:32 -S 2
1285 fi | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1288 # use isohybrid as default
1290 if ! which isohybrid >/dev/null 2>&1 ; then
1291 bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1293 log "Creating hybrid ISO file with isohybrid method"
1294 einfo "Creating hybrid ISO file with isohybrid method"
1295 # Notes for consideration:
1296 # "-entry 4 -type 1c"
1297 # * using 4 as the partition number is supposed to help with BIOSes
1298 # that only support USB-Zip boot
1299 # * using 1c (i.e. hidden FAT32 LBA), instead of the default 0x17
1300 # (hidden NTFS, IIRC), as the partition type is sometimes needed
1301 # to get the BIOS even look at the partition created by isohybrid
1302 if isohybrid --help | grep -q -- --uefi ; then
1303 einfo "Detected uefi support for isohybrid, enabling."
1304 ISOHYBRID_OPTIONS=--uefi
1307 log "isohybrid $ISOHYBRID_OPTIONS ${ISO_OUTPUT}/${ISO_NAME}"
1308 isohybrid $ISOHYBRID_OPTIONS "${ISO_OUTPUT}/${ISO_NAME}"
1313 # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1314 case $CLASSES in *RELEASE*)
1317 if cd $ISO_OUTPUT ; then
1318 md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1319 touch -r ${ISO_NAME} ${ISO_NAME}.md5
1320 sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1321 touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1330 if [ "$RC" = 0 ] ; then
1331 log "Finished execution of stage 'iso build' [$(date)]"
1332 einfo "Finished execution of stage 'iso build'" ; eend 0
1334 log "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1335 eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1341 # pack artifacts {{{
1342 if [ -n "$PACK_ARTIFACTS" ]; then
1343 log "Packing artifcats"
1344 einfo "Packing artifacts"
1345 [ -f "${CHROOT_ARCHIVE}" ] && rm -r "${CHROOT_ARCHIVE}"
1346 tar -c -a -f ${CHROOT_ARCHIVE} --preserve-permissions -C "$(dirname ${CHROOT_OUTPUT})" "$(basename ${CHROOT_OUTPUT})"
1351 # log build information to database if grml-live-db is installed and enabled {{{
1353 if [ -d /usr/share/grml-live-db ] ; then
1356 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1357 [ -n "$DPKG_DATABASE" ] || DPKG_DATABASE=/var/log/grml-live.db
1358 [ -n "$DPKG_DBSCRIPT" ] || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1359 [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1361 if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1362 log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1363 eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1367 # disable by default for now, not sure whether really everyone is using a local db file
1368 #if ! touch "$DPKG_DATABASE" ; then
1369 # eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1373 if ! [ -r "$DPKG_LIST" ] ; then
1374 log "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1375 ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1377 einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1378 log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1379 log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1382 if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1398 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1399 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1401 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1403 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1407 ## END OF FILE #################################################################
1408 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2