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 # command line parsing {{{
287 while getopts "a:C:c:d:D:g:i:I:o:r:s:t:T:U:v:AbBFnNquVz" opt; do
290 A) PACK_ARTIFACTS=1 ;;
293 c) CLASSES="$OPTARG" ;;
294 C) GRML_LIVE_LOCAL_CONFIG="$OPTARG" ;;
296 D) GRML_FAI_CONFIG="$OPTARG" ;;
297 g) GRML_NAME="$OPTARG" ;;
298 i) ISO_NAME="$OPTARG" ;;
299 I) CHROOT_INSTALL="$OPTARG" ;;
301 N) BOOTSTRAP_ONLY=1; SKIP_MKISOFS=1; SKIP_MKSQUASHFS=1 ;;
302 o) OUTPUT="$OPTARG" ;;
303 q) SKIP_MKSQUASHFS=1 ;;
304 r) RELEASENAME="$OPTARG" ;;
305 s) SUITE="$OPTARG" ;;
306 t) TEMPLATE_DIRECTORY="$OPTARG";;
307 T) UNPACK_CHROOT="$(readlink -f $OPTARG)" ;;
308 v) VERSION="$OPTARG" ;;
311 U) CHOWN_USER="$OPTARG" ;;
313 z) SQUASHFS_ZLIB=1 ;;
314 ?) echo "invalid option -$OPTARG" >&2; bailout 1 ;;
317 shift $(($OPTIND - 1)) # set ARGV to the first not parsed commandline parameter
320 # read local (non-packaged) configuration {{{
321 if [ -z "$GRML_LIVE_LOCAL_CONFIG" ]; then
322 if [ -r "/etc/grml/grml-live.local" ]; then
323 GRML_LIVE_LOCAL_CONFIG="/etc/grml/grml-live.local"
326 if [ -n "$GRML_LIVE_LOCAL_CONFIG" ]; then
327 if [ -r "$GRML_LIVE_LOCAL_CONFIG" ]; then
328 . $GRML_LIVE_LOCAL_CONFIG
330 eerror "Could not read specified local configuration file \"$GRML_LIVE_LOCAL_CONFIG\"."
333 GRML_LIVE_LOCAL_CONFIG=$(readlink -f "$GRML_LIVE_LOCAL_CONFIG")
335 GRML_LIVE_LOCAL_CONFIG=''
338 if [ -n "${GRML_LIVE_SOURCES:-}" ] ; then
339 eerror "Config variable \$GRML_LIVE_SOURCES is set. This variable has been deprecated."
340 ewarn "Please set up \${GRML_FAI_CONFIG}/config/files/etc/apt/sources.list.d/* instead."
345 # assume sane defaults (if not set already) {{{
346 [ -n "$ARCH" ] || ARCH="$(dpkg --print-architecture)"
347 [ -n "$BOOT_METHOD" ] || BOOT_METHOD='isolinux'
348 [ -n "$CLASSES" ] || CLASSES="GRMLBASE,GRML_FULL,$(echo ${ARCH} | tr 'a-z' 'A-Z')"
349 [ -n "$DATE" ] || DATE="$(date +%Y-%m-%d)"
350 [ -n "$DISTRI_INFO" ] || DISTRI_INFO='Grml - Live Linux for system administrators '
351 [ -n "$DISTRI_NAME" ] || DISTRI_NAME="grml"
352 [ -n "$DISTRI_SPLASH" ] || DISTRI_SPLASH='grml.png'
353 [ -n "$FORCE_ISO_REBUILD" ] || FORCE_ISO_REBUILD="false"
354 [ -n "$GRML_FAI_CONFIG" ] || GRML_FAI_CONFIG='/etc/grml/fai'
355 [ -n "$GRML_NAME" ] || GRML_NAME='grml'
356 [ -n "$HOSTNAME" ] || HOSTNAME='grml'
357 [ -n "$HYBRID_METHOD" ] || HYBRID_METHOD='manifold'
358 [ -n "$NFSROOT_CONF" ] || NFSROOT_CONF="${GRML_FAI_CONFIG}/make-fai-nfsroot.conf"
359 [ -n "$RELEASENAME" ] || RELEASENAME='grml-live rocks'
360 [ -n "$SQUASHFS_EXCLUDES_FILE" ] || SQUASHFS_EXCLUDES_FILE="${GRML_FAI_CONFIG}/config/grml/squashfs-excludes"
361 [ -n "$SUITE" ] || SUITE='squeeze'
362 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
363 [ -n "$USERNAME" ] || USERNAME='grml'
364 [ -n "$VERSION" ] || VERSION='0.0.1'
366 # output specific stuff, depends on $OUTPUT (iff not set):
367 [ -n "$OUTPUT" ] || OUTPUT='/grml/grml-live'
368 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
369 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
370 [ -n "$CHROOT_ARCHIVE" ] || CHROOT_ARCHIVE="$OUTPUT/$(basename $CHROOT_OUTPUT).tgz"
371 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
372 [ -n "$LOG_OUTPUT" ] || LOG_OUTPUT="$OUTPUT/grml_logs"
373 [ -n "$REPORTS" ] || REPORTS="${LOG_OUTPUT}/reports/"
376 # some misc checks before executing FAI {{{
377 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
378 specify it on the command line using the -c option."
379 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
380 specify it on the command line using the -o option."
382 # trim characters that are known to cause problems inside $GRML_NAME;
383 # for example isolinux does not like '-' inside the directory name
384 [ -n "$GRML_NAME" ] && export SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
386 # export variables to have them available in fai scripts:
387 [ -n "$GRML_NAME" ] && export GRML_NAME="$GRML_NAME"
388 [ -n "$RELEASENAME" ] && export RELEASENAME="$RELEASENAME"
391 # ZERO_LOGFILE - check for backwards compatibility reasons {{{
392 # this was default behaviour until grml-live 0.9.34:
393 if [ -n "$ZERO_LOGFILE" ] ; then
394 PRESERVE_LOGFILE='' # make sure it's cleaned then
395 ewarn "Please consider disabling the \$ZERO_LOGFILE option as grml-live clears..."
396 ewarn "... the logfile $LOGFILE by default (unless \$PRESERVE_LOGFILE is set) nowadays."
401 # ask user whether the setup is ok {{{
402 if [ -z "$FORCE" ] ; then
404 echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
406 echo " FAI classes: $CLASSES"
407 [ -n "$GRML_LIVE_LOCAL_CONFIG" ] && echo " Configuration: $GRML_LIVE_LOCAL_CONFIG"
408 [ -n "$GRML_FAI_CONFIG" ] && echo " Config directory: $GRML_FAI_CONFIG"
409 echo " main directory: $OUTPUT"
410 [ -n "$UNPACK_CHROOT" ] && echo " Chroot from: $UNPACK_CHROOT"
411 [ -n "$CHROOT_OUTPUT" ] && echo " Chroot target: $CHROOT_OUTPUT"
412 [ -n "$BUILD_OUTPUT" ] && echo " Build target: $BUILD_OUTPUT"
413 [ -n "$ISO_OUTPUT" ] && echo " ISO target: $ISO_OUTPUT"
414 [ -n "$GRML_NAME" ] && echo " Grml name: $GRML_NAME"
415 [ -n "$RELEASENAME" ] && echo " Release name: $RELEASENAME"
416 [ -n "$DATE" ] && echo " Build date: $DATE"
417 [ -n "$VERSION" ] && echo " Grml version: $VERSION"
418 [ -n "$SUITE" ] && echo " Debian suite: $SUITE"
419 [ -n "$ARCH" ] && echo " Architecture: $ARCH"
420 [ -n "$BOOT_METHOD" ] && echo " Boot method: $BOOT_METHOD"
421 [ -n "$HYBRID_METHOD" ] && echo " Hybrid method: $HYBRID_METHOD"
422 [ -n "$TEMPLATE_DIRECTORY" ] && echo " Template files: $TEMPLATE_DIRECTORY"
423 [ -n "$CHROOT_INSTALL" ] && echo " Install files from directory to chroot: $CHROOT_INSTALL"
424 [ -n "$BOOTID" ] && echo " Boot identifier: $BOOTID"
425 [ -n "$NO_BOOTID" ] && echo " Skipping bootid feature."
426 [ -n "$CHOWN_USER" ] && echo " Output owner: $CHOWN_USER"
427 [ -n "$DEFAULT_BOOTOPTIONS" ] && echo " Adding default bootoptions: \"$DEFAULT_BOOTOPTIONS\""
428 [ -n "$FAI_ARGS" ] && echo " Additional arguments for FAI: $FAI_ARGS"
429 [ -n "$LOGFILE" ] && echo " Logging to file: $LOGFILE"
430 [ -n "$SQUASHFS_ZLIB" ] && echo " Using ZLIB (instead of LZMA/XZ) compression."
431 [ -n "$SQUASHFS_OPTIONS" ] && echo " Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
432 [ -n "$VERBOSE" ] && echo " Using VERBOSE mode."
433 [ -n "$PACK_ARTIFACTS" ] && echo " Will prepare packed artifacts and ensure clean build."
434 [ -n "$UPDATE" ] && echo " Executing UPDATE instead of fresh installation."
435 if [ -n "$BOOTSTRAP_ONLY" ] ; then
436 echo " Bootstrapping only and not building (files for) ISO."
438 [ -n "$SKIP_MKSQUASHFS" ] && echo " Skipping creation of SQUASHFS file."
439 [ -n "$SKIP_MKISOFS" ] && echo " Skipping creation of ISO file."
440 [ -n "$BUILD_ONLY" ] && echo " Executing BUILD_ONLY instead of fresh installation or UPDATE."
441 [ -n "$BUILD_DIRTY" ] && echo " Executing BUILD_DIRTY to leave chroot untouched."
444 echo -n "Is this ok for you? [y/N] "
446 if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
447 bailout 1 "Exiting as requested."
453 # clean up before start {{{
454 if [ -n "${PACK_ARTIFACTS}" ]; then
455 echo "Wiping old artifacts"
456 [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && rm -r "${CHROOT_OUTPUT}"
457 [ -n "${BUILD_OUTPUT}" -a -d "${BUILD_OUTPUT}" ] && rm -r "${BUILD_OUTPUT}"
458 [ -n "${ISO_OUTPUT}" -a -d "${ISO_OUTPUT}" ] && rm -r "${ISO_OUTPUT}"
459 [ -n "${LOG_OUTPUT}" -a -d "${LOG_OUTPUT}" ] && rm -r "${LOG_OUTPUT}"
463 # create log file {{{
464 [ -n "$LOGFILE" ] || LOGFILE=${LOG_OUTPUT}/grml-live.log
465 mkdir -p $(dirname "${LOGFILE}")
467 chown root:adm $LOGFILE
471 # clean/zero/remove logfiles {{{
473 if [ -n "$PRESERVE_LOGFILE" ] ; then
474 echo "Preserving logfile $LOGFILE as requested via \$PRESERVE_LOGFILE"
476 # make sure it is empty (as it is e.g. appended to grml-live-db)
480 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
481 if [ -d /var/log/fai/"$HOSTNAME" ] ; then
482 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
483 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
484 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
485 rm -f /var/log/fai/"$HOSTNAME"/last \
486 /var/log/fai/"$HOSTNAME"/last-dirinstall \
487 /var/log/fai/"$HOSTNAME"/last-softupdate
492 # source config and startup {{{
493 if [ -n "$CONFIG" ] ; then
494 if ! [ -f "$CONFIG" ] ; then
495 log "Error: $CONFIG could not be read. Exiting. [$(date)]"
496 eerror "Error: $CONFIG could not be read. Exiting." ; eend 1
499 log "Sourcing $CONFIG"
504 start_seconds=$(cut -d . -f 1 /proc/uptime)
505 log "------------------------------------------------------------------------------"
506 log "Starting grml-live [${GRML_LIVE_VERSION}] run on $(date)"
507 log "Using local config file: $GRML_LIVE_LOCAL_CONFIG"
508 log "Executed grml-live command line:"
511 einfo "Logging actions to logfile $LOGFILE"
515 if [ -n "${UNPACK_CHROOT}" ]; then
516 log "Unpacking chroot from ${UNPACK_CHROOT}"
517 einfo "Unpacking chroot from ${UNPACK_CHROOT}"
518 [ -d "$CHROOT_OUTPUT" ] || mkdir -p "${CHROOT_OUTPUT}"
519 tar -xf "${UNPACK_CHROOT}" -C "${CHROOT_OUTPUT}/" --strip-components 1 | RC=$?
521 if [ "$RC" != 0 ] ; then
529 # cleanup CHROOT_ARCHIVE now {{{
530 if [ -n "${PACK_ARTIFACTS}" ]; then
531 # can't do this earlier, as UNPACK_CHROOT might point to CHROOT_ARCHIVE
532 [ -n "${CHROOT_ARCHIVE}" -a -f "${CHROOT_ARCHIVE}" ] && rm "${CHROOT_ARCHIVE}"
536 # on-the-fly configuration {{{
537 if [ -n "$FAI_DEBOOTSTRAP" ] ; then
538 sed "s#^FAI_DEBOOTSTRAP=.*#FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"#" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
541 # does this suck? YES!
542 # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
544 unstable) SUITE='sid' ; CLASSES="DEBIAN_UNSTABLE,$CLASSES" ;;
545 *) CLASSES="DEBIAN_$(echo $SUITE | tr 'a-z' 'A-Z'),$CLASSES";;
547 export SUITE # make sure it's available in FAI scripts
549 for file in "$LIVE_CONF" "$GRML_LIVE_LOCAL_CONFIG" "$NFSROOT_CONF" ; do
550 if [ -n "$file" ] ; then
551 sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
555 # validate whether the specified architecture class matches the
556 # architecture (option), otherwise installation of kernel will fail
557 if echo $CLASSES | grep -qi i386 ; then
558 if ! [[ "$ARCH" == "i386" ]] ; then
559 log "Error: You specified the I386 class but are trying to build something else (AMD64?)."
560 eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
561 eerror "Tip: Either invoke grml-live with '-a i386' or adjust the architecture class. Exiting."
565 elif echo $CLASSES | grep -qi amd64 ; then
566 if ! [[ "$ARCH" == "amd64" ]] ; then
567 log "Error: You specified the AMD64 class but are trying to build something else (I386?)."
568 eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
569 eerror "Tip: Either invoke grml-live with '-a amd64' or adjust the architecture class. Exiting."
575 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
576 sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
578 sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
582 # CHROOT_OUTPUT - execute FAI {{{
583 if [ -n "$BUILD_DIRTY" ]; then
584 log "Skipping stage 'fai' as requested via option -B"
585 ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
587 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
589 # provide inform fai about the ISO we build
590 [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
591 echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
592 [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
593 [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
595 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
596 FAI_ACTION=softupdate
598 FAI_ACTION=dirinstall
601 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
602 if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
603 log "Error: does not look like you have a working chroot. Updating/building not possible."
604 eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
610 if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
611 log "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
612 ewarn "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
614 mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
616 if [ -n "${MIRROR_DIRECTORY}" ] ; then
617 mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
618 mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
621 mkdir -p "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
622 mount --bind "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
624 # tell dpkg to use "unsafe io" during the build
625 [ -d "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d" ] || mkdir -p "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d"
626 echo force-unsafe-io > "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
628 log "Executed FAI command line:"
629 log "BUILD_ONLY=$BUILD_ONLY BOOTSTRAP_ONLY=$BOOTSTRAP_ONLY GRML_LIVE_LOCAL_CONFIG=$GRML_LIVE_LOCAL_CONFIG fai $VERBOSE -C $GRML_FAI_CONFIG -s file:///$GRML_FAI_CONFIG/config -c$CLASSES -u $HOSTNAME $FAI_ACTION $CHROOT_OUTPUT $FAI_ARGS"
630 BUILD_ONLY="$BUILD_ONLY" BOOTSTRAP_ONLY="$BOOTSTRAP_ONLY" GRML_LIVE_LOCAL_CONFIG="$GRML_LIVE_LOCAL_CONFIG" fai $VERBOSE \
631 -C "$GRML_FAI_CONFIG" -s "file:///$GRML_FAI_CONFIG/config" -c"$CLASSES" \
632 -u "$HOSTNAME" "$FAI_ACTION" "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
633 RC="$PIPESTATUS" # notice: bash-only
635 rm -f "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
637 FORCE_ISO_REBUILD=true
639 if [ "$RC" != 0 ] ; then
640 log "Error: critical error while executing fai [exit code ${RC}]. Exiting."
641 eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
644 einfo "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
645 log "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
646 echo "$GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]" > $CHROOT_OUTPUT/etc/grml_version
647 chmod 644 $CHROOT_OUTPUT/etc/grml_version
648 einfo "Rebuilding initramfs"
649 # make sure new /etc/grml_version reaches initramfs, iterate over all
650 # present kernel versions (note: we can't really handle more than one
651 # kernel version anyway right now)
652 # chroot $CHROOT_OUTPUT update-initramfs -u -t => might break when using kernel-package :(
653 for initrd in "$(basename $CHROOT_OUTPUT/boot/vmlinuz-*)" ; do
654 if ! chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -c ; then
655 einfo "Creating fresh initrd did not work, trying update instead:"
656 log "Creating fresh initrd did not work, trying update instead:"
657 chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -u
663 # move fai logs into grml_logs directory
664 mkdir -p "$LOG_OUTPUT"/fai/
665 cp -r "$CHROOT_OUTPUT"/var/log/fai/"$HOSTNAME"/last/* "$LOG_OUTPUT"/fai/
666 rm -rf "$CHROOT_OUTPUT"/var/log/fai
667 # copy fai package list
668 cp "$CHROOT_OUTPUT"/var/log/install_packages.list "$LOG_OUTPUT"/fai/
670 chown root:adm "$LOG_OUTPUT"/fai/*
671 chmod 664 "$LOG_OUTPUT"/fai/*
675 # notice: 'fai dirinstall' does not seem to exit appropriate, so:
677 CHECKLOG="$LOG_OUTPUT"/fai/
678 if [ -r "$CHECKLOG/software.log" ] ; then
679 # 1 errors during executing of commands
680 grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
681 grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
682 grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
683 grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
684 grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
687 if [ -r "$CHECKLOG/shell.log" ] ; then
688 grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=6
691 if [ -n "$ERROR" ] ; then
692 log "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
693 eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
694 eerror "Note: check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
698 log "Finished execution of stage 'fai dirinstall' [$(date)]"
699 einfo "Finished execution of stage 'fai dirinstall'"
705 # package validator {{{
706 CHECKLOG=/var/log/fai/$HOSTNAME/last
707 if [ -r "$CHECKLOG/dpkg.selections" ] ; then
708 package_count=$(wc -l "$CHECKLOG/dpkg.selections" | awk '{print $1}')
710 package_count="unknown"
714 REPORT_MISSING_PACKAGES="${REPORTS}/TEST-MissingPackages.xml"
716 # check for missing packages
717 if ! [ -s "$CHECKLOG/package_errors.log" ] ; then
718 einfo "No missing packages found, generating empty junit report."
720 cat > "${REPORT_MISSING_PACKAGES}" << EOF
721 <?xml version="1.0" encoding="UTF-8"?>
722 <testsuite name="grml-live-missing-packages" tests="${package_count}" time="1" failures="0" errors="0" skipped="0" assertions="0">
723 <testcase name="test_missing_packages" time="0" assertions="0">
733 einfo "Missing packages found, generating junit report."
735 if [ -r "$CHECKLOG/package_errors.log" ] ; then
736 package_errors=$(wc -l "$CHECKLOG/package_errors.log" | awk '{print $1}')
738 package_errors="unknown"
742 REPORT_MISSING_PACKAGES="${REPORTS}/TEST-MissingPackages.xml"
744 cat > "${REPORT_MISSING_PACKAGES}" << EOF
745 <?xml version="1.0" encoding="UTF-8"?>
746 <testsuite name="grml-live-missing-packages" tests="${package_count}" time="1" failures="${package_errors}" errors="${package_errors}" skipped="0" assertions="0">
749 for package in $(awk '{print $5}' "${CHECKLOG}/package_errors.log" | sed 's/\.$//') ; do
750 cat >> "${REPORT_MISSING_PACKAGES}" << EOF
751 <testcase name="test_missing_packages_${package}" time="0" assertions="0">
752 <failure type="RuntimeError" message="Package ${package} is missing">
753 Package $package is missing in chroot
759 cat >> "${REPORT_MISSING_PACKAGES}" << EOF
768 if [ -n "$EXIT_ON_MISSING_PACKAGES" -a -z "$BUILD_DIRTY" ] ; then
769 eerror "The following packages were requested for installation but could not be processed:"
770 cat "$CHECKLOG/package_errors.log"
771 eerror "... exiting as requested via \$EXIT_ON_MISSING_PACKAGES."
775 ewarn "The following packages were requested for installation but could not be processed:"
776 cat "$CHECKLOG/package_errors.log"
782 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
783 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
784 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
787 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
788 if [ -n "$BOOTSTRAP_ONLY" ] ; then
789 log "Skipping stage 'boot' as building with bootstrap only."
790 ewarn "Skipping stage 'boot' as building with bootstrap only." ; eend 0
792 if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
793 log "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already."
794 ewarn "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already." ; eend 0
797 [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
798 [ -d "$BUILD_OUTPUT"/boot/"${SHORT_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
800 # if we don't have an initrd we a) can't boot and b) there was an error
801 # during build, so check for the file:
802 INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
803 if [ -n "$INITRD" ] ; then
804 cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.gz
805 find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
807 log "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
808 eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
812 KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
813 if [ -n "$KERNEL_IMAGE" ] ; then
814 cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/linux26
816 log "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
817 eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
821 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
822 if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
823 log "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
824 eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
828 # copy _required_ isolinux files
829 for file in ifcpu64.c32 isolinux.bin vesamenu.c32; do
830 copy_addon_file "${file}" /usr/lib/syslinux isolinux
833 # *always* copy files to output directory so the variables
834 # get adjusted according to the build.
835 cp ${TEMPLATE_DIRECTORY}/boot/isolinux/* "$BUILD_OUTPUT"/boot/isolinux/
837 if [ -n "$NO_ADDONS" ] ; then
838 log "Skipping installation of boot addons as requested via \$NO_ADDONS."
839 einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
841 if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
842 log "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
843 ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
845 # copy addons from system packages or grml-live-compat
846 copy_addon_file ipxe.lkrn /usr/lib/ipxe addons
847 copy_addon_file pci.ids /usr/share/misc addons
848 copy_addon_file memtest86+.bin /boot addons
849 for file in memdisk chain.c32 hdt.c32 menu.c32; do
850 copy_addon_file "${file}" /usr/lib/syslinux addons
853 # make memtest filename FAT16/8.3 compatible
854 mv "${BUILD_OUTPUT}/boot/addons/memtest86+.bin" \
855 "${BUILD_OUTPUT}/boot/addons/memtest"
857 # copy only files so we can handle bsd4grml on its own
858 for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
859 test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
862 if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
863 log "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
864 einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
866 if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
867 cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
869 log "Missing addon file: bsd4grml"
870 ewarn "Missing addon file: bsd4grml" ; eend 0
874 fi # no "$TEMPLATE_DIRECTORY"/boot/addons
877 if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
878 mkdir -p "${BUILD_OUTPUT}/boot/grub"
880 cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
882 if [ -e ${TEMPLATE_DIRECTORY}/compat/grub/linux.mod ]; then
883 cp "${TEMPLATE_DIRECTORY}"/compat/grub/* "${BUILD_OUTPUT}"/boot/grub/
885 if ! which "grub-mkimage" >/dev/null 2>&1 ; then
886 log "grub-mkimage not found, skipping Grub step therefore." ; eend 0
887 ewarn "grub-mkimage not found, skipping Grub step therefore."
888 ewarn "Please install grub-pc-bin or grub-common >= 1.98+20100804-14." ; eend 0
889 elif ! grub-mkimage --help | grep -q -- --format ; then
890 log "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore." ; eend 0
891 ewarn "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore."
892 ewarn "Please install grub-common >= 1.98+20100804-14 or grub-pc-bin." ; eend 0
894 # copy system grub files if grml-live-compat is not installed
895 cp -a /usr/lib/grub/*-pc/*.mod "${BUILD_OUTPUT}"/boot/grub/
896 cp -a /usr/lib/grub/*-pc/*.o "${BUILD_OUTPUT}"/boot/grub/
897 cp -a /usr/lib/grub/*-pc/*.lst "${BUILD_OUTPUT}"/boot/grub/
898 cp -a /usr/share/grub/ascii.pf2 "${BUILD_OUTPUT}"/boot/grub/
899 grub-mkimage -d /usr/lib/grub/*-pc -o \
900 "${BUILD_OUTPUT}/boot/grub/core.img" biosdisk iso9660 --format=i386-pc
904 if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
905 log "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
906 eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
910 [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
911 cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
913 # adjust boot splash information:
914 RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
915 RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
916 RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
918 if [ -r "$BUILD_OUTPUT"/GRML/grml-version ] ; then
919 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
920 sed -i "s/%DATE%/$DATE/" "$BUILD_OUTPUT"/GRML/grml-version
923 # make sure the squashfs filename is set accordingly:
924 SQUASHFS_NAME="$GRML_NAME.squashfs"
926 if [ -n "$NO_BOOTID" ] ; then
927 log 'Skipping bootid feature as requested via $NO_BOOTID.'
928 einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
930 [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
931 [ -d "$BUILD_OUTPUT"/conf ] || mkdir "$BUILD_OUTPUT"/conf
932 einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
933 log "Generating /conf/bootid.txt with entry ${BOOTID}."
934 echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
938 # adjust all variables in the templates with the according distribution information
939 for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
940 "${BUILD_OUTPUT}"/boot/grub/* ; do
941 if [ -r "${file}" ] ; then
942 sed -i "s/%ARCH%/$ARCH/g" "${file}"
943 sed -i "s/%DATE%/$DATE/g" "${file}"
944 sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g" "${file}"
945 sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g" "${file}"
946 sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g" "${file}"
947 sed -i "s/%GRML_NAME%/$GRML_NAME/g" "${file}"
948 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g" "${file}"
949 sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g" "${file}"
950 sed -i "s/%SHORT_NAME%/$SHORT_NAME/g" "${file}"
951 sed -i "s/%VERSION%/$VERSION/g" "${file}"
953 [ -n "$DEFAULT_BOOTOPTIONS" ] && sed -i "s/ boot=live/ boot=live $DEFAULT_BOOTOPTIONS/" "${file}"
955 if [ -n "$NO_BOOTID" ] ; then
956 sed -i "s/ bootid=%BOOTID%//g" "${file}" # drop bootid bootoption
958 sed -i "s/%BOOTID%/$BOOTID/g" "${file}" # adjust bootid=... argument
963 # adjust bootsplash accordingly but make sure the string has the according lenght
964 SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
965 SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
966 for file in f4 f5 ; do
967 if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
968 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
969 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
973 # generate addon list
974 rm -f "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
975 for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
976 include_name=$(basename "$name")
977 echo "include $include_name" >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
980 if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
981 log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
982 echo "include grmlmain.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
983 echo "include default.cfg" > "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
984 echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
985 echo "include grml.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
987 for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
988 echo "include $(basename $f)" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
991 echo "include options.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
992 if [ ! -n "$NO_ADDONS" ] ; then
993 echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
995 echo "include isoprompt.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
996 echo "include hd.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
997 echo "include hidden.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
998 else # assume we are building a custom distribution:
999 log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
1000 einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
1001 if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
1002 log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
1004 einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
1008 log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1009 echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1010 [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1014 # use old style console based isolinux method only if requested:
1015 if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
1016 log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
1017 einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
1018 if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
1019 einfo "include for console.cfg already found, nothing to do."
1022 log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1023 einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1024 echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1028 log 'Using graphical boot menu.'
1029 if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
1030 log "include for vesamenu.cfg already found, nothing to do."
1032 log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1033 echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1037 if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
1038 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
1041 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
1042 if ! [ -r "$DPKG_LIST" ] ; then
1043 ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
1045 einfo "Storing package list information as /GRML/${GRML_NAME}-packages.txt on ISO."
1046 cp "$DPKG_LIST" "${BUILD_OUTPUT}/GRML/${GRML_NAME}-packages.txt"
1050 # autostart for Windows:
1051 if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
1052 cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
1055 FORCE_ISO_REBUILD=true
1056 einfo "Finished execution of stage 'boot'" ; eend 0
1060 log 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
1061 eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
1065 # support installation of local files into the chroot/ISO
1066 if [ -n "$CHROOT_INSTALL" ] ; then
1067 if ! [ -d "$CHROOT_INSTALL" ] ; then
1068 log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1069 ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1071 log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1072 einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1073 rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
1075 einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
1076 FORCE_ISO_REBUILD=true
1080 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
1081 log "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
1082 ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
1083 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
1084 log "Skipping stage 'squashfs' as requested via option -q or -N"
1085 ewarn "Skipping stage 'squashfs' as requested via option -q or -N" ; eend 0
1087 [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
1088 # make sure we don't leave (even an empty) base.tgz:
1089 [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
1091 # if unconfigured default to squashfs-tools' mksquashfs binary
1092 if [ -z "$SQUASHFS_BINARY" ] ; then
1093 SQUASHFS_BINARY='mksquashfs'
1096 if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
1097 log "Using mksquashfs binary ${SQUASHFS_BINARY}"
1098 einfo "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
1100 log "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
1101 eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
1105 # use sane defaults if $SQUASHFS_OPTIONS isn't set
1106 if [ -z "$SQUASHFS_OPTIONS" ] ; then
1107 # use blocksize 256k as this gives best result with regards to time + compression
1108 SQUASHFS_OPTIONS="-b 256k"
1110 # set lzma/xz compression by default, unless -z option has been specified on command line
1111 if [ -z "$SQUASHFS_ZLIB" ] ; then
1112 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp xz"
1114 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp gzip"
1118 # support exclusion of files via exclude-file:
1119 if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
1120 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE -wildcards"
1123 # get rid of unnecessary files when building grml-small for final release:
1124 if echo "$CLASSES" | grep -q GRML_SMALL ; then
1125 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
1129 SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
1131 # informational stuff
1132 [ -n "$SQUASHFS_OPTIONS" ] && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
1133 [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
1134 einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
1136 log "$SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS"
1138 if $SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
1139 -noappend $SQUASHFS_OPTIONS 2>"${SQUASHFS_STDERR}" ; then
1140 echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
1141 log "Finished execution of stage 'squashfs' [$(date)]"
1142 einfo "Finished execution of stage 'squashfs'" ; eend 0
1144 log "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1145 log "$(cat $SQUASHFS_STDERR)"
1146 eerror "Error: there was a critical error executing stage 'squashfs':"
1147 cat "${SQUASHFS_STDERR}"
1152 FORCE_ISO_REBUILD=true
1155 # create md5sum file:
1156 if [ -z "$BOOTSTRAP_ONLY" ] ; then
1157 ( cd $BUILD_OUTPUT/GRML &&
1158 find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1162 # ISO_OUTPUT - mkisofs {{{
1163 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1164 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1166 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1167 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1168 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1169 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1172 # Just until http://bts.grml.org/grml/issue945 has been resolved.
1173 # HYBRID_METHOD defaults to manifold, so make sure the default works OOTB.
1174 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1175 log "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1176 ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1177 HYBRID_METHOD='grub2'
1181 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ] ; then
1182 log "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1183 ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1184 elif [ -n "$SKIP_MKISOFS" ] ; then
1185 log "Skipping stage 'iso build' as requested via option -n or -N"
1186 ewarn "Skipping stage 'iso build' as requested via option -n or -N" ; eend 0
1188 mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1190 if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1191 log "Forcing rebuild of ISO because files on ISO have been modified."
1192 einfo "Forcing rebuild of ISO because files on ISO have been modified."
1195 # support xorriso as well mkisofs and genisoimage
1196 if which xorriso >/dev/null 2>&1 && \
1197 dpkg --compare-versions $(dpkg-query -W -f='${Version}\n' xorriso 2>/dev/null) gt-nl 1.1.6-2 ; then
1198 MKISOFS='xorriso -as mkisofs'
1199 elif which mkisofs >/dev/null 2>&1; then
1201 elif which genisoimage >/dev/null 2>&1; then
1202 MKISOFS='genisoimage'
1204 log "Error: neither xorriso nor mkisofs nor genisoimage available - can not create ISO."
1205 eerror "Error: neither xorriso nor mkisofs nor genisoimage available - can not create ISO." ; eend 1
1211 # using -eltorito-alt-boot is limited to xorriso for now
1214 einfo "Using xorriso for ISO generation." ; eend 0
1216 if [ -r "${CHROOT_OUTPUT}/var/lib/grml_live_efi.img" ] ; then
1217 einfo "Found /var/lib/grml_live_efi.img - moving to /boot/efi.img for ISO."
1218 log "Found /var/lib/grml_live_efi.img - moving to /boot/efi.img for ISO."
1219 mv "${CHROOT_OUTPUT}/var/lib/grml_live_efi.img" "${BUILD_OUTPUT}/boot/efi.img"
1223 if [ -r "${CHROOT_OUTPUT}/var/lib/grml_live_bootx64.efi" ] ; then
1224 einfo "Found /var/lib/grml_live_bootx64.efi - moving to /efi/boot/bootx64.efi for ISO"
1225 log "Found /var/lib/grml_live_bootx64.efi - moving to /efi/boot/bootx64.efi for ISO"
1226 mkdir -p "${BUILD_OUTPUT}/efi/boot/"
1227 mv "${CHROOT_OUTPUT}/var/lib/grml_live_bootx64.efi" "${BUILD_OUTPUT}/efi/boot/bootx64.efi"
1231 if [ -r "${BUILD_OUTPUT}"/boot/efi.img ] ; then
1232 einfo "/boot/efi.img found and amd64 architecture present, extending boot arguments."
1233 log "/boot/efi.img found and amd64 architecture present, extending boot arguments."
1234 BOOT_ARGS="$BOOT_ARGS -boot-info-table -eltorito-alt-boot -e boot/efi.img -no-emul-boot"
1243 if cd "$BUILD_OUTPUT" ; then
1244 if [ "$BOOT_METHOD" = "grub2" ]; then
1245 # make a 2048-byte bootsector for El Torito
1246 dd if=/dev/zero of=boot/grub/toriboot.bin bs=512 count=4 2>/dev/null
1247 # those are in 2048-byte sectors, so 1 16 matches 4 63 below
1248 echo 1 16 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -B 11 | \
1249 dd of=boot/grub/toriboot.bin conv=notrunc 2>/dev/null
1251 log "$MKISOFS -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J $BOOT_ARGS -o ${ISO_OUTPUT}/${ISO_NAME} ."
1252 $MKISOFS -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1253 -l -r -J $BOOT_ARGS -no-pad \
1254 -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1255 # both of these need core.img there, so it’s easier to write it here
1256 if [ "$BOOT_METHOD" = "grub2" ] || [ "$HYBRID_METHOD" = "grub2" ]; then
1257 # must be <= 30720 bytes
1258 dd if=boot/grub/core.img of="${ISO_OUTPUT}/${ISO_NAME}" \
1259 conv=notrunc bs=512 seek=4 2>/dev/null
1262 # pad the output ISO to multiples of 256 KiB for partition table support
1263 siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1264 cyls=$((siz / 512 / 32 / 16 + 1)) # C=$cyls H=16 S=32
1265 siz=$((cyls * 16 * 32 * 512)) # size after padding
1266 dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1267 of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1269 # support disabling hybrid ISO image
1270 if [ "$HYBRID_METHOD" = "disable" ] ; then\
1271 log "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1272 einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1274 elif [ "$HYBRID_METHOD" = "manifold" ] ; then
1275 # isoinfo is part of both mkisofs and genisoimage so we're good
1276 bootoff=$(isoinfo -l -i "${ISO_OUTPUT}/${ISO_NAME}" | \
1277 sed -n '/^.*\[ *\([0-9]*\)[] ].* ISOLINUX.BIN[;1]* *$/s//\1/p')
1278 if ! [ -r boot/grub/core.img ] ; then
1279 ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1280 elif [ "${bootoff:-0}" -lt 1 ] ; then
1281 ewarn "isolinux.bin not found on the ISO file, disabling manifold boot"
1283 log "Creating hybrid ISO file with manifold method"
1284 einfo "Creating hybrid ISO file with manifold method"
1285 if [ "$HYBRID_METHOD" = "grub2" ] ; then
1286 # 512 bytes: MBR, partition table, load GRUB 2
1287 echo 4 63 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 4:0x96 -g $cyls:16:32
1289 # read only one but 2048-byte sized (scale: << 2) sector
1290 echo $bootoff $bootoff | \
1291 mksh /usr/share/grml-live/scripts/bootilnx.mksh -A -M 4:0x96 -g $cyls:16:32 -S 2
1292 fi | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1295 # use isohybrid as default
1297 if ! which isohybrid >/dev/null 2>&1 ; then
1298 bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1300 log "Creating hybrid ISO file with isohybrid method"
1301 einfo "Creating hybrid ISO file with isohybrid method"
1302 # Notes for consideration:
1303 # "-entry 4 -type 1c"
1304 # * using 4 as the partition number is supposed to help with BIOSes
1305 # that only support USB-Zip boot
1306 # * using 1c (i.e. hidden FAT32 LBA), instead of the default 0x17
1307 # (hidden NTFS, IIRC), as the partition type is sometimes needed
1308 # to get the BIOS even look at the partition created by isohybrid
1309 if isohybrid --help | grep -q -- --uefi ; then
1310 einfo "Detected uefi support for isohybrid, enabling."
1311 ISOHYBRID_OPTIONS=--uefi
1314 log "isohybrid $ISOHYBRID_OPTIONS ${ISO_OUTPUT}/${ISO_NAME}"
1315 isohybrid $ISOHYBRID_OPTIONS "${ISO_OUTPUT}/${ISO_NAME}"
1320 # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1321 case $CLASSES in *RELEASE*)
1324 if cd $ISO_OUTPUT ; then
1325 md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1326 touch -r ${ISO_NAME} ${ISO_NAME}.md5
1327 sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1328 touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1337 if [ "$RC" = 0 ] ; then
1338 log "Finished execution of stage 'iso build' [$(date)]"
1339 einfo "Finished execution of stage 'iso build'" ; eend 0
1341 log "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1342 eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1348 # pack artifacts {{{
1349 if [ -n "$PACK_ARTIFACTS" ]; then
1350 log "Packing artifcats"
1351 einfo "Packing artifacts"
1352 [ -f "${CHROOT_ARCHIVE}" ] && rm -r "${CHROOT_ARCHIVE}"
1353 tar -c -a -f ${CHROOT_ARCHIVE} --preserve-permissions -C "$(dirname ${CHROOT_OUTPUT})" "$(basename ${CHROOT_OUTPUT})"
1358 # log build information to database if grml-live-db is installed and enabled {{{
1360 if [ -d /usr/share/grml-live-db ] ; then
1363 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1364 [ -n "$DPKG_DATABASE" ] || DPKG_DATABASE=/var/log/grml-live.db
1365 [ -n "$DPKG_DBSCRIPT" ] || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1366 [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1368 if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1369 log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1370 eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1374 # disable by default for now, not sure whether really everyone is using a local db file
1375 #if ! touch "$DPKG_DATABASE" ; then
1376 # eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1380 if ! [ -r "$DPKG_LIST" ] ; then
1381 log "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1382 ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1384 einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1385 log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1386 log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1389 if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1405 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1406 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1408 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1410 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1414 ## END OF FILE #################################################################
1415 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2