3 # Purpose: build process script for generating a (grml based) Linux Live-ISO
4 # Authors: grml-team (grml.org),
5 # (c) Michael Prokop <mika@grml.org>,
6 # (c) Thorsten Glaser <tg@mirbsd.org>
7 # Bug-Reports: see http://grml.org/bugs/
8 # License: This file is licensed under the GPL v2 or any later version.
9 ################################################################################
11 # some misc and global stuff {{{
15 # define function getfilesize before "set -e"
16 if stat --help >/dev/null 2>&1; then
17 getfilesize='stat -c %s' # GNU stat
19 getfilesize='stat -f %z' # BSD stat
23 # disable for now since it seems to cause some problems
27 GRML_LIVE_VERSION='0.16.1'
30 ADDONS_LIST_FILE='/boot/isolinux/addons_list.cfg'
33 # usage information {{{
37 $PN - build process script for generating a (grml based) Linux Live-ISO
39 Usage: $PN [options, see as follows]
41 -a <architecture> architecture; available values: i386 and amd64
42 -A ensure clean build and pack artifacts
43 -b build the ISO without updating the chroot via FAI
44 -B build the ISO without touching the chroot (skips cleanup)
45 -c <classe[s]> classes to be used for building the ISO via FAI
46 -C <configfile> configuration file for grml-live
47 -d <date> use specified date instead of build time as date of release
48 -D <configdir> use specified configuration directory instead of /etc/grml/fai
49 -F force execution without prompting
50 -g <grml_name> set the grml flavour name
51 -h display short usage information and exit
52 -i <iso_name> name of ISO
53 -I <src_directory> directory which provides files that should become
54 part of the chroot/ISO
55 -n skip generation of ISO
56 -N bootstrap (build chroot) only, do not create files for ISO
57 -o <output_directory> main output directory of the build process
59 -r <release_name> release name
60 -s <suite> Debian suite; values: etch, lenny, squeeze, sid
61 -t <template_directory> place of the templates
62 -u update existing chroot instead of rebuilding it from scratch
63 -U <username> arrange output to be owned by specified username
64 -v <version_number> specify version number of the release
65 -V increase verbosity in the build process
66 -z use ZLIB instead of LZMA/XZ compression
71 $PN -c GRMLBASE,GRML_FULL,AMD64 -o /dev/shm/grml
72 $PN -c GRMLBASE,GRML_FULL,AMD64 -i grml_0.0-1.iso -v 0.0-1
73 $PN -c GRMLBASE,GRML_FULL,AMD64 -s sid -V -r 'grml-live rocks'
75 More details: man grml-live + /usr/share/doc/grml-live/grml-live.html
76 http://grml.org/grml-live/
78 Please send your bug reports and feedback to the grml-team: http://grml.org/bugs/
82 # make sure it's possible to get usage information without being
83 # root or actually executing the script
84 if [ "$1" = '-h' -o "$1" = '--help' ] ; then
86 [ "$(id -u 2>/dev/null)" != 0 ] && echo "Please notice that this script requires root permissions."
91 # some runtime checks {{{
92 # we need root permissions for the build-process:
93 if [ "$(id -u 2>/dev/null)" != 0 ] ; then
94 echo "Error: please run this script with uid 0 (root)." >&2
98 if [ -r /var/run/fai/FAI_INSTALLATION_IN_PROGRESS ] ; then
99 echo "/usr/sbin/fai already running or was aborted before.">&2
100 echo "You may remove /var/run/fai/FAI_INSTALLATION_IN_PROGRESS and try again.">&2
105 if [ -r /var/run/fai/fai_softupdate_is_running ] ; then
106 echo "/usr/sbin/fai softupdate already running or was aborted before.">&2
107 echo "You may remove /var/run/fai/fai_softupdate_is_running and try again.">&2
112 # lsb-functions and configuration stuff {{{
113 # make sure they are not set by default
122 # don't use colors/escape sequences
123 if [ -r /lib/lsb/init-functions ] ; then
124 . /lib/lsb/init-functions
125 ! log_use_fancy_output && NOCOLORS=true
128 if [ -r /etc/grml/lsb-functions ] ; then
129 . /etc/grml/lsb-functions
131 einfo() { echo " [*] $*" ;}
132 eerror() { echo " [!] $*">&2 ;}
133 ewarn() { echo " [x] $*" ;}
135 eindent() { return 0 ;}
136 eoutdent() { return 0 ;}
139 # source main configuration file:
140 LIVE_CONF=/etc/grml/grml-live.conf
144 # umount all directories {{{
146 # make sure we don't leave any mounts - FAI doesn't remove them always
147 umount $CHROOT_OUTPUT/proc 2>/dev/null || /bin/true
148 umount $CHROOT_OUTPUT/sys 2>/dev/null || /bin/true
149 umount $CHROOT_OUTPUT/dev/pts 2>/dev/null || /bin/true
150 umount $CHROOT_OUTPUT/dev 2>/dev/null || /bin/true
151 umount "${CHROOT_OUTPUT}/grml-live/sources/" 2>/dev/null || /bin/true
152 [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
158 rm -f /var/run/fai/fai_softupdate_is_running \
159 /var/run/fai/FAI_INSTALLATION_IN_PROGRESS
160 [ -n "$SQUASHFS_STDERR" ] && rm -rf "$SQUASHFS_STDERR"
162 [ -n "$1" ] && EXIT="$1" || EXIT="1"
163 [ -n "$2" ] && eerror "$2">&2
164 if [ -n "$PACK_ARTIFACTS" ]; then
167 [ -n "${BUILD_OUTPUT}" -a -d "${BUILD_OUTPUT}" ] && rm -r "${BUILD_OUTPUT}"
168 [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && rm -r "${CHROOT_OUTPUT}"
171 if [ -n "$CHOWN_USER" ]; then
172 log "Setting ownership"
173 einfo "Setting ownership"
174 [ -n "${OUTPUT}" -a -d "${OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${OUTPUT}"
175 [ -n "${BUILD_OUTPUT}" -a -d "${BUILD_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${BUILD_OUTPUT}"
176 [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${CHROOT_OUTPUT}"
177 [ -n "${ISO_OUTPUT}" -a -d "${ISO_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${ISO_OUTPUT}"
178 [ -n "${LOG_OUTPUT}" -a -d "${LOG_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${LOG_OUTPUT}"
179 [ -n "${CHROOT_ARCHIVE}" -a -f "${CHROOT_ARCHIVE}" ] && chown -R "${CHOWN_USER}:" "${CHROOT_ARCHIVE}"
182 log "------------------------------------------------------------------------------"
185 trap bailout 1 2 3 3 6 9 14 15
189 # some important functions {{{
192 # usage: log "string to log"
193 log() { echo "$*" >> $LOGFILE ; }
195 # cut string at character number int = $1
196 # usage: cut_string 5 "1234567890" will output "12345"
198 [ -n "$2" ] || return 1
199 echo "$2" | head -c "$1"; echo -ne "\n"
202 # prepend int = $1 spaces before string = $2
203 # usage: extend_string_begin 5 "123" will output " 123"
204 extend_string_begin() {
205 [ -n "$2" ] || return 1
206 local COUNT="$(echo $2 | wc -c)"
207 local FILL="$(expr $COUNT - $1)"
208 while [ "$FILL" -gt 1 ] ; do
210 local FILL=$(expr $FILL - 1)
212 while [ "$FILL" -lt 1 ] ; do
214 local FILL=$(expr $FILL + 1)
216 echo "$2" | head -c "$1"; echo -ne "\n"
219 # append int = $1 spaces to string = $2
220 # usage: extend_string_begin 5 "123" will output "123 "
221 extend_string_end() {
222 [ -n "$2" ] || return 1
223 echo -n "$2" | head -c "$1"
224 local COUNT="$(echo $2 | wc -c)"
225 local FILL="$(expr $COUNT - $1)"
226 while [ "$FILL" -gt 1 ] ; do
228 local FILL=$(expr $FILL - 1)
230 while [ "$FILL" -lt 1 ] ; do
232 local FILL=$(expr $FILL + 1)
237 # Copy addonfile $1 from either
238 # * the chroot (via $2, the system path),
239 # * or from TEMPLATE_DIRECTORY/compat (if exists),
240 # * or from the host system (again, using $2),
241 # or warn about the missing file.
244 # * We assume that the chroot always has a "good" version of
245 # the file. Also it makes sources handling easier.
246 # * On unstable, we Recommend the Debian packages containing
247 # these files. The user can override them by putting his
248 # "better" version into the chroot.
249 # * On stable, the Debian packages are probably not available,
250 # or outdated, so we look in TEMPLATE_DIRECTORY/compat first, where
251 # our grml-live-compat package installs current file versions.
253 DEST="${BUILD_OUTPUT}/boot/$3"
254 if [ ! -d "${DEST}/" ]; then
257 if [ -e "$CHROOT_OUTPUT/$2/$1" ]; then
258 log "Copying $1 from chroot"
259 cp "$CHROOT_OUTPUT/$2/$1" "${DEST}/"
262 if [ -e "${TEMPLATE_DIRECTORY}/compat/$3/$1" ]; then
263 log "Copying $1 from grml-live-compat"
264 cp "${TEMPLATE_DIRECTORY}/compat/$3/$1" "${DEST}/"
267 if [ -e "$2/$1" ]; then
268 log "Copying $1 from system"
269 cp "$2/$1" "${DEST}/"
273 msg="Missing addon file: \"$1\""
274 ewarn "$msg" ; eend 1
275 log "copy_addon_file: $msg"
279 # read local (non-packaged) configuration {{{
280 LOCAL_CONFIG=/etc/grml/grml-live.local
281 if [ -r "$LOCAL_CONFIG" ] ; then
287 if [ -n "${GRML_LIVE_SOURCES:-}" ] ; then
288 eerror "Config variable \$GRML_LIVE_SOURCES is set. This variable has been deprecated."
289 ewarn "Please set up ${GRML_FAI_CONFIG}/config/files/etc/apt/sources.list.d/* instead."
294 # command line parsing {{{
295 while getopts "a:C:c:d:D:g:i:I:o:r:s:t:U:v:AbBFnNquVz" opt; do
298 A) PACK_ARTIFACTS=1 ;;
301 c) CLASSES="$OPTARG" ;;
302 C) CONFIG="$OPTARG" ;;
304 D) GRML_FAI_CONFIG="$OPTARG" ;;
305 g) GRML_NAME="$OPTARG" ;;
306 i) ISO_NAME="$OPTARG" ;;
307 I) CHROOT_INSTALL="$OPTARG" ;;
309 N) BOOTSTRAP_ONLY=1; SKIP_MKISOFS=1; SKIP_MKSQUASHFS=1 ;;
310 o) OUTPUT="$OPTARG" ;;
311 q) SKIP_MKSQUASHFS=1 ;;
312 r) RELEASENAME="$OPTARG" ;;
313 s) SUITE="$OPTARG" ;;
314 t) TEMPLATE_DIRECTORY="$OPTARG";;
315 v) VERSION="$OPTARG" ;;
318 U) CHOWN_USER="$OPTARG" ;;
320 z) SQUASHFS_ZLIB=1 ;;
321 ?) echo "invalid option -$OPTARG" >&2; bailout 1 ;;
324 shift $(($OPTIND - 1)) # set ARGV to the first not parsed commandline parameter
327 # assume sane defaults (if not set already) {{{
328 [ -n "$ARCH" ] || ARCH="$(dpkg --print-architecture)"
329 [ -n "$BOOT_METHOD" ] || BOOT_METHOD='isolinux'
330 [ -n "$CLASSES" ] || CLASSES="GRMLBASE,GRML_MEDIUM,$(echo ${ARCH} | tr 'a-z' 'A-Z')"
331 [ -n "$DATE" ] || DATE="$(date +%Y-%m-%d)"
332 [ -n "$DISTRI_INFO" ] || DISTRI_INFO='Grml - Live Linux for system administrators '
333 [ -n "$DISTRI_NAME" ] || DISTRI_NAME="grml"
334 [ -n "$DISTRI_SPLASH" ] || DISTRI_SPLASH='grml.png'
335 [ -n "$FORCE_ISO_REBUILD" ] || FORCE_ISO_REBUILD="false"
336 [ -n "$GRML_FAI_CONFIG" ] || GRML_FAI_CONFIG='/etc/grml/fai'
337 [ -n "$GRML_NAME" ] || GRML_NAME='grml'
338 [ -n "$HOSTNAME" ] || HOSTNAME='grml'
339 [ -n "$HYBRID_METHOD" ] || HYBRID_METHOD='manifold'
340 [ -n "$NFSROOT_CONF" ] || NFSROOT_CONF="${GRML_FAI_CONFIG}/make-fai-nfsroot.conf"
341 [ -n "$RELEASENAME" ] || RELEASENAME='grml-live rocks'
342 [ -n "$SQUASHFS_EXCLUDES_FILE" ] || SQUASHFS_EXCLUDES_FILE="${GRML_FAI_CONFIG}/config/grml/squashfs-excludes"
343 [ -n "$SUITE" ] || SUITE='squeeze'
344 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
345 [ -n "$USERNAME" ] || USERNAME='grml'
346 [ -n "$VERSION" ] || VERSION='0.0.1'
348 # output specific stuff, depends on $OUTPUT (iff not set):
349 [ -n "$OUTPUT" ] || OUTPUT='/grml/grml-live'
350 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
351 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
352 [ -n "$CHROOT_ARCHIVE" ] || CHROOT_ARCHIVE="$OUTPUT/$(basename $CHROOT_OUTPUT).tgz"
353 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
354 [ -n "$LOG_OUTPUT" ] || LOG_OUTPUT="$OUTPUT/grml_logs"
357 # some misc checks before executing FAI {{{
358 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
359 specify it on the command line using the -c option."
360 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
361 specify it on the command line using the -o option."
363 # trim characters that are known to cause problems inside $GRML_NAME;
364 # for example isolinux does not like '-' inside the directory name
365 [ -n "$GRML_NAME" ] && export SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
367 # export variables to have them available in fai scripts:
368 [ -n "$GRML_NAME" ] && export GRML_NAME="$GRML_NAME"
369 [ -n "$RELEASENAME" ] && export RELEASENAME="$RELEASENAME"
372 # ZERO_LOGFILE - check for backwards compatibility reasons {{{
373 # this was default behaviour until grml-live 0.9.34:
374 if [ -n "$ZERO_LOGFILE" ] ; then
375 PRESERVE_LOGFILE='' # make sure it's cleaned then
376 ewarn "Please consider disabling the \$ZERO_LOGFILE option as grml-live clears..."
377 ewarn "... the logfile $LOGFILE by default (unless \$PRESERVE_LOGFILE is set) nowadays."
382 # ask user whether the setup is ok {{{
383 if [ -z "$FORCE" ] ; then
385 echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
387 echo " FAI classes: $CLASSES"
388 [ -r "$LOCAL_CONFIG" ] && echo " Local config: /etc/grml/grml-live.local"
389 [ -n "$CONFIG" ] && echo " Configuration: $CONFIG"
390 [ -n "$GRML_FAI_CONFIG" ] && echo " Config directory: $GRML_FAI_CONFIG"
391 echo " main directory: $OUTPUT"
392 [ -n "$CHROOT_OUTPUT" ] && echo " Chroot target: $CHROOT_OUTPUT"
393 [ -n "$BUILD_OUTPUT" ] && echo " Build target: $BUILD_OUTPUT"
394 [ -n "$ISO_OUTPUT" ] && echo " ISO target: $ISO_OUTPUT"
395 [ -n "$GRML_NAME" ] && echo " Grml name: $GRML_NAME"
396 [ -n "$RELEASENAME" ] && echo " Release name: $RELEASENAME"
397 [ -n "$DATE" ] && echo " Build date: $DATE"
398 [ -n "$VERSION" ] && echo " Grml version: $VERSION"
399 [ -n "$SUITE" ] && echo " Debian suite: $SUITE"
400 [ -n "$ARCH" ] && echo " Architecture: $ARCH"
401 [ -n "$BOOT_METHOD" ] && echo " Boot method: $BOOT_METHOD"
402 [ -n "$HYBRID_METHOD" ] && echo " Hybrid method: $HYBRID_METHOD"
403 [ -n "$TEMPLATE_DIRECTORY" ] && echo " Template files: $TEMPLATE_DIRECTORY"
404 [ -n "$CHROOT_INSTALL" ] && echo " Install files from directory to chroot: $CHROOT_INSTALL"
405 [ -n "$BOOTID" ] && echo " Boot identifier: $BOOTID"
406 [ -n "$NO_BOOTID" ] && echo " Skipping bootid feature."
407 [ -n "$CHOWN_USER" ] && echo " Output owner: $CHOWN_USER"
408 [ -n "$DEFAULT_BOOTOPTIONS" ] && echo " Adding default bootoptions: \"$DEFAULT_BOOTOPTIONS\""
409 [ -n "$FAI_ARGS" ] && echo " Additional arguments for FAI: $FAI_ARGS"
410 [ -n "$LOGFILE" ] && echo " Logging to file: $LOGFILE"
411 [ -n "$SQUASHFS_ZLIB" ] && echo " Using ZLIB (instead of LZMA/XZ) compression."
412 [ -n "$SQUASHFS_OPTIONS" ] && echo " Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
413 [ -n "$VERBOSE" ] && echo " Using VERBOSE mode."
414 [ -n "$PACK_ARTIFACTS" ] && echo " Will prepare packed artifacts and ensure clean build."
415 [ -n "$UPDATE" ] && echo " Executing UPDATE instead of fresh installation."
416 if [ -n "$BOOTSTRAP_ONLY" ] ; then
417 echo " Bootstrapping only and not building (files for) ISO."
419 [ -n "$SKIP_MKSQUASHFS" ] && echo " Skipping creation of SQUASHFS file."
420 [ -n "$SKIP_MKISOFS" ] && echo " Skipping creation of ISO file."
421 [ -n "$BUILD_ONLY" ] && echo " Executing BUILD_ONLY instead of fresh installation or UPDATE."
422 [ -n "$BUILD_DIRTY" ] && echo " Executing BUILD_DIRTY to leave chroot untouched."
425 echo -n "Is this ok for you? [y/N] "
427 if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
428 bailout 1 "Exiting as requested."
434 # clean up before start {{{
435 if [ -n "${PACK_ARTIFACTS}" ]; then
436 echo "Wiping old artifacts"
437 [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && rm -r "${CHROOT_OUTPUT}"
438 [ -n "${BUILD_OUTPUT}" -a -d "${BUILD_OUTPUT}" ] && rm -r "${BUILD_OUTPUT}"
439 [ -n "${ISO_OUTPUT}" -a -d "${ISO_OUTPUT}" ] && rm -r "${ISO_OUTPUT}"
440 [ -n "${LOG_OUTPUT}" -a -d "${LOG_OUTPUT}" ] && rm -r "${LOG_OUTPUT}"
441 [ -n "${CHROOT_ARCHIVE}" -a -f "${CHROOT_ARCHIVE}" ] && rm "${CHROOT_ARCHIVE}"
445 # create log file {{{
446 [ -n "$LOGFILE" ] || LOGFILE=${LOG_OUTPUT}/grml-live.log
447 mkdir -p $(dirname "${LOGFILE}")
449 chown root:adm $LOGFILE
453 # clean/zero/remove logfiles {{{
455 if [ -n "$PRESERVE_LOGFILE" ] ; then
456 echo "Preserving logfile $LOGFILE as requested via \$PRESERVE_LOGFILE"
458 # make sure it is empty (as it is e.g. appended to grml-live-db)
462 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
463 if [ -d /var/log/fai/"$HOSTNAME" ] ; then
464 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
465 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
466 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
467 rm -f /var/log/fai/"$HOSTNAME"/last \
468 /var/log/fai/"$HOSTNAME"/last-dirinstall \
469 /var/log/fai/"$HOSTNAME"/last-softupdate
474 # source config and startup {{{
475 if [ -n "$CONFIG" ] ; then
476 if ! [ -f "$CONFIG" ] ; then
477 log "Error: $CONFIG could not be read. Exiting. [$(date)]"
478 eerror "Error: $CONFIG could not be read. Exiting." ; eend 1
481 log "Sourcing $CONFIG"
486 start_seconds=$(cut -d . -f 1 /proc/uptime)
487 log "------------------------------------------------------------------------------"
488 log "Starting grml-live [${GRML_LIVE_VERSION}] run on $(date)"
489 if [ -n "$LOCAL_CONFIG" ]; then
490 log "Using local config file: $LOCAL_CONFIG"
492 log "Executed grml-live command line:"
495 einfo "Logging actions to logfile $LOGFILE"
498 # on-the-fly configuration {{{
499 if [ -n "$FAI_DEBOOTSTRAP" ] ; then
500 sed "s#^FAI_DEBOOTSTRAP=.*#FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"#" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
503 # does this suck? YES!
504 # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
506 unstable) SUITE='sid' ; CLASSES="DEBIAN_UNSTABLE,$CLASSES" ;;
507 *) CLASSES="DEBIAN_$(echo $SUITE | tr 'a-z' 'A-Z'),$CLASSES";;
509 export SUITE # make sure it's available in FAI scripts
511 for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" "$NFSROOT_CONF" ; do
512 if [ -n "$file" ] ; then
513 sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
517 # validate whether the specified architecture class matches the
518 # architecture (option), otherwise installation of kernel will fail
519 if echo $CLASSES | grep -qi i386 ; then
520 if ! [[ "$ARCH" == "i386" ]] ; then
521 log "Error: You specified the I386 class but are trying to build something else (AMD64?)."
522 eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
523 eerror "Tip: Either invoke grml-live with '-a i386' or adjust the architecture class. Exiting."
527 elif echo $CLASSES | grep -qi amd64 ; then
528 if ! [[ "$ARCH" == "amd64" ]] ; then
529 log "Error: You specified the AMD64 class but are trying to build something else (I386?)."
530 eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
531 eerror "Tip: Either invoke grml-live with '-a amd64' or adjust the architecture class. Exiting."
537 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
538 sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
540 sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
544 # CHROOT_OUTPUT - execute FAI {{{
545 if [ -n "$BUILD_DIRTY" ]; then
546 log "Skipping stage 'fai' as requested via option -B"
547 ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
549 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
551 # provide inform fai about the ISO we build
552 [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
553 echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
554 [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
555 [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
557 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
558 FAI_ACTION=softupdate
560 FAI_ACTION=dirinstall
563 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
564 if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
565 log "Error: does not look like you have a working chroot. Updating/building not possible."
566 eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
572 if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
573 log "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
574 ewarn "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
576 mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
578 if [ -n "${MIRROR_DIRECTORY}" ] ; then
579 mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
580 mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
583 mkdir -p "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
584 mount --bind "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
586 # tell dpkg to use "unsafe io" during the build
587 [ -d "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d" ] || mkdir -p "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d"
588 echo force-unsafe-io > "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
590 log "Executed FAI command line:"
591 log "BUILD_ONLY=$BUILD_ONLY BOOTSTRAP_ONLY=$BOOTSTRAP_ONLY fai $VERBOSE -C $GRML_FAI_CONFIG -s file:///$GRML_FAI_CONFIG/config -c$CLASSES -u $HOSTNAME $FAI_ACTION $CHROOT_OUTPUT $FAI_ARGS"
592 BUILD_ONLY="$BUILD_ONLY" BOOTSTRAP_ONLY="$BOOTSTRAP_ONLY" fai $VERBOSE \
593 -C "$GRML_FAI_CONFIG" -s "file:///$GRML_FAI_CONFIG/config" -c"$CLASSES" \
594 -u "$HOSTNAME" "$FAI_ACTION" "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
595 RC="$PIPESTATUS" # notice: bash-only
597 rm -f "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
599 FORCE_ISO_REBUILD=true
601 if [ "$RC" != 0 ] ; then
602 log "Error: critical error while executing fai [exit code ${RC}]. Exiting."
603 eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
606 einfo "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
607 log "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
608 echo "$GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]" > $CHROOT_OUTPUT/etc/grml_version
609 chmod 644 $CHROOT_OUTPUT/etc/grml_version
610 einfo "Rebuilding initramfs"
611 # make sure new /etc/grml_version reaches initramfs, iterate over all
612 # present kernel versions (note: we can't really handle more than one
613 # kernel version anyway right now)
614 # chroot $CHROOT_OUTPUT update-initramfs -u -t => might break when using kernel-package :(
615 for initrd in "$(basename $CHROOT_OUTPUT/boot/vmlinuz-*)" ; do
616 if ! chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -c ; then
617 einfo "Creating fresh initrd did not work, trying update instead:"
618 log "Creating fresh initrd did not work, trying update instead:"
619 chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -u
625 # move fai logs into grml_logs directory
626 mkdir -p "$LOG_OUTPUT"/fai/
627 cp -r "$CHROOT_OUTPUT"/var/log/fai/"$HOSTNAME"/last/* "$LOG_OUTPUT"/fai/
628 chown root:adm "$LOG_OUTPUT"/fai/*
629 chmod 664 "$LOG_OUTPUT"/fai/*
630 rm -rf "$CHROOT_OUTPUT"/var/log/fai
632 # Remove all FAI logs from chroot if class RELEASE is used:
633 rm -f "$CHROOT_OUTPUT"/var/log/install_packages.list
637 # notice: 'fai dirinstall' does not seem to exit appropriate, so:
639 CHECKLOG=/var/log/fai/$HOSTNAME/last
640 if [ -r "$CHECKLOG/software.log" ] ; then
641 # 1 errors during executing of commands
642 grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
643 grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
644 grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
645 grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
646 grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
649 if [ -r "$CHECKLOG/shell.log" ] ; then
650 grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=6
653 if [ -n "$ERROR" ] ; then
654 log "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
655 eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
656 eerror "Note: check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
660 log "Finished execution of stage 'fai dirinstall' [$(date)]"
661 einfo "Finished execution of stage 'fai dirinstall'"
664 einfo "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
665 log "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
671 # package validator {{{
672 CHECKLOG=/var/log/fai/$HOSTNAME/last
674 if [ -r "$CHECKLOG/package_errors.log" ] && grep -q '[a-z]' "$CHECKLOG/package_errors.log" ; then
676 if [ -n "$EXIT_ON_MISSING_PACKAGES" -a -z "$BUILD_DIRTY" ] ; then
677 eerror "The following packages were requested for installation but could not be processed:"
678 cat $CHECKLOG/package_errors.log
679 eerror "... exiting as requested via \$EXIT_ON_MISSING_PACKAGES."
683 ewarn "The following packages were requested for installation but could not be processed:"
684 cat $CHECKLOG/package_errors.log
690 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
691 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
692 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
695 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
696 if [ -n "$BOOTSTRAP_ONLY" ] ; then
697 log "Skipping stage 'boot' as building with bootstrap only."
698 ewarn "Skipping stage 'boot' as building with bootstrap only." ; eend 0
700 if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
701 log "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already."
702 ewarn "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already." ; eend 0
705 [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
706 [ -d "$BUILD_OUTPUT"/boot/"${SHORT_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
708 # if we don't have an initrd we a) can't boot and b) there was an error
709 # during build, so check for the file:
710 INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
711 if [ -n "$INITRD" ] ; then
712 cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.gz
713 find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
715 log "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
716 eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
720 KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
721 if [ -n "$KERNEL_IMAGE" ] ; then
722 cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/linux26
724 log "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
725 eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
729 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
730 if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
731 log "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
732 eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
736 # copy _required_ isolinux files
737 for file in ifcpu64.c32 isolinux.bin vesamenu.c32; do
738 copy_addon_file "${file}" /usr/lib/syslinux isolinux
741 # *always* copy files to output directory so the variables
742 # get adjusted according to the build.
743 cp ${TEMPLATE_DIRECTORY}/boot/isolinux/* "$BUILD_OUTPUT"/boot/isolinux/
745 if [ -n "$NO_ADDONS" ] ; then
746 log "Skipping installation of boot addons as requested via \$NO_ADDONS."
747 einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
749 if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
750 log "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
751 ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
753 # copy addons from system packages or grml-live-compat
754 copy_addon_file ipxe.lkrn /usr/lib/ipxe addons
755 copy_addon_file pci.ids /usr/share/misc addons
756 copy_addon_file memtest86+.bin /boot addons
757 for file in memdisk chain.c32 hdt.c32 menu.c32; do
758 copy_addon_file "${file}" /usr/lib/syslinux addons
761 # make memtest filename FAT16/8.3 compatible
762 mv "${BUILD_OUTPUT}/boot/addons/memtest86+.bin" \
763 "${BUILD_OUTPUT}/boot/addons/memtest"
765 # copy only files so we can handle bsd4grml on its own
766 for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
767 test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
770 if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
771 log "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
772 einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
774 if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
775 cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
777 log "Missing addon file: bsd4grml"
778 ewarn "Missing addon file: bsd4grml" ; eend 0
782 fi # no "$TEMPLATE_DIRECTORY"/boot/addons
785 if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
786 mkdir -p "${BUILD_OUTPUT}/boot/grub"
788 cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
790 if [ -e ${TEMPLATE_DIRECTORY}/compat/grub/linux.mod ]; then
791 cp "${TEMPLATE_DIRECTORY}"/compat/grub/* "${BUILD_OUTPUT}"/boot/grub/
793 if ! which "grub-mkimage" >/dev/null 2>&1 ; then
794 log "grub-mkimage not found, skipping Grub step therefore." ; eend 0
795 ewarn "grub-mkimage not found, skipping Grub step therefore."
796 ewarn "Please install grub-pc-bin or grub-common >= 1.98+20100804-14." ; eend 0
797 elif ! grub-mkimage --help | grep -q -- --format ; then
798 log "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore." ; eend 0
799 ewarn "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore."
800 ewarn "Please install grub-common >= 1.98+20100804-14 or grub-pc-bin." ; eend 0
802 # copy system grub files if grml-live-compat is not installed
803 cp -a /usr/lib/grub/*-pc/*.mod "${BUILD_OUTPUT}"/boot/grub/
804 cp -a /usr/lib/grub/*-pc/*.o "${BUILD_OUTPUT}"/boot/grub/
805 cp -a /usr/lib/grub/*-pc/*.lst "${BUILD_OUTPUT}"/boot/grub/
806 cp -a /usr/share/grub/ascii.pf2 "${BUILD_OUTPUT}"/boot/grub/
807 grub-mkimage -d /usr/lib/grub/*-pc -o \
808 "${BUILD_OUTPUT}/boot/grub/core.img" biosdisk iso9660 --format=i386-pc
812 if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
813 log "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
814 eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
818 [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
819 cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
821 # adjust boot splash information:
822 RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
823 RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
824 RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
826 if [ -r "$BUILD_OUTPUT"/GRML/grml-version ] ; then
827 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
828 sed -i "s/%DATE%/$DATE/" "$BUILD_OUTPUT"/GRML/grml-version
831 # make sure the squashfs filename is set accordingly:
832 SQUASHFS_NAME="$GRML_NAME.squashfs"
834 if [ -n "$NO_BOOTID" ] ; then
835 log 'Skipping bootid feature as requested via $NO_BOOTID.'
836 einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
838 [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
839 [ -d "$BUILD_OUTPUT"/conf ] || mkdir "$BUILD_OUTPUT"/conf
840 einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
841 log "Generating /conf/bootid.txt with entry ${BOOTID}."
842 echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
846 # adjust all variables in the templates with the according distribution information
847 for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
848 "${BUILD_OUTPUT}"/boot/grub/* ; do
849 if [ -r "${file}" ] ; then
850 sed -i "s/%ARCH%/$ARCH/g" "${file}"
851 sed -i "s/%DATE%/$DATE/g" "${file}"
852 sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g" "${file}"
853 sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g" "${file}"
854 sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g" "${file}"
855 sed -i "s/%GRML_NAME%/$GRML_NAME/g" "${file}"
856 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g" "${file}"
857 sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g" "${file}"
858 sed -i "s/%SHORT_NAME%/$SHORT_NAME/g" "${file}"
859 sed -i "s/%VERSION%/$VERSION/g" "${file}"
861 [ -n "$DEFAULT_BOOTOPTIONS" ] && sed -i "s/ boot=live/ boot=live $DEFAULT_BOOTOPTIONS/" "${file}"
863 if [ -n "$NO_BOOTID" ] ; then
864 sed -i "s/ bootid=%BOOTID%//g" "${file}" # drop bootid bootoption
866 sed -i "s/%BOOTID%/$BOOTID/g" "${file}" # adjust bootid=... argument
871 # adjust bootsplash accordingly but make sure the string has the according lenght
872 SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
873 SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
874 for file in f4 f5 ; do
875 if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
876 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
877 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
881 # generate addon list
882 rm -f "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
883 for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
884 include_name=$(basename "$name")
885 echo "include $include_name" >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
888 if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
889 log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
890 echo "include grmlmain.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
891 echo "include default.cfg" > "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
892 echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
893 echo "include grml.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
895 for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
896 echo "include $(basename $f)" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
899 echo "include options.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
900 if [ ! -n "$NO_ADDONS" ] ; then
901 echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
903 echo "include isoprompt.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
904 echo "include hd.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
905 echo "include hidden.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
906 else # assume we are building a custom distribution:
907 log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
908 einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
909 if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
910 log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
912 einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
916 log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
917 echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
918 [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
922 # use old style console based isolinux method only if requested:
923 if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
924 log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
925 einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
926 if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
927 einfo "include for console.cfg already found, nothing to do."
930 log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
931 einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
932 echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
936 log 'Using graphical boot menu.'
937 if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
938 log "include for vesamenu.cfg already found, nothing to do."
940 log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
941 echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
945 if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
946 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
949 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
950 if ! [ -r "$DPKG_LIST" ] ; then
951 ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
953 einfo "Storing package list information as /GRML/${GRML_NAME}-packages.txt on ISO."
954 cp "$DPKG_LIST" "${BUILD_OUTPUT}/GRML/${GRML_NAME}-packages.txt"
958 # autostart for Windows:
959 if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
960 cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
963 FORCE_ISO_REBUILD=true
964 einfo "Finished execution of stage 'boot'" ; eend 0
968 log 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
969 eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
973 # support installation of local files into the chroot/ISO
974 if [ -n "$CHROOT_INSTALL" ] ; then
975 if ! [ -d "$CHROOT_INSTALL" ] ; then
976 log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
977 ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
979 log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
980 einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
981 rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
983 einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
984 FORCE_ISO_REBUILD=true
988 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
989 log "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
990 ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
991 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
992 log "Skipping stage 'squashfs' as requested via option -q or -N"
993 ewarn "Skipping stage 'squashfs' as requested via option -q or -N" ; eend 0
995 [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
996 # make sure we don't leave (even an empty) base.tgz:
997 [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
999 # if unconfigured default to squashfs-tools' mksquashfs binary
1000 if [ -z "$SQUASHFS_BINARY" ] ; then
1001 SQUASHFS_BINARY='mksquashfs'
1004 if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
1005 log "Using mksquashfs binary ${SQUASHFS_BINARY}"
1006 einfo "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
1008 log "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
1009 eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
1013 # use sane defaults if $SQUASHFS_OPTIONS isn't set
1014 if [ -z "$SQUASHFS_OPTIONS" ] ; then
1015 # use blocksize 256k as this gives best result with regards to time + compression
1016 SQUASHFS_OPTIONS="-b 256k"
1018 # set lzma/xz compression by default, unless -z option has been specified on command line
1019 if [ -z "$SQUASHFS_ZLIB" ] ; then
1020 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp xz"
1022 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp gzip"
1026 # support exclusion of files via exclude-file:
1027 if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
1028 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE -wildcards"
1031 # get rid of unnecessary files when building grml-small for final release:
1032 if echo "$CLASSES" | grep -q GRML_SMALL ; then
1033 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
1037 SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
1039 # informational stuff
1040 [ -n "$SQUASHFS_OPTIONS" ] && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
1041 [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
1042 einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
1044 log "$SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS"
1046 if $SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
1047 -noappend $SQUASHFS_OPTIONS 2>"${SQUASHFS_STDERR}" ; then
1048 echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
1049 log "Finished execution of stage 'squashfs' [$(date)]"
1050 einfo "Finished execution of stage 'squashfs'" ; eend 0
1052 log "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1053 log "$(cat $SQUASHFS_STDERR)"
1054 eerror "Error: there was a critical error executing stage 'squashfs':"
1055 cat "${SQUASHFS_STDERR}"
1060 FORCE_ISO_REBUILD=true
1063 # create md5sum file:
1064 if [ -z "$BOOTSTRAP_ONLY" ] ; then
1065 ( cd $BUILD_OUTPUT/GRML &&
1066 find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1070 # ISO_OUTPUT - mkisofs {{{
1071 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1072 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1074 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1075 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1076 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1077 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1080 # Just until http://bts.grml.org/grml/issue945 has been resolved.
1081 # HYBRID_METHOD defaults to manifold, so make sure the default works OOTB.
1082 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1083 log "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1084 ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1085 HYBRID_METHOD='grub2'
1089 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ] ; then
1090 log "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1091 ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1092 elif [ -n "$SKIP_MKISOFS" ] ; then
1093 log "Skipping stage 'iso build' as requested via option -n or -N"
1094 ewarn "Skipping stage 'iso build' as requested via option -n or -N" ; eend 0
1096 mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1098 if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1099 log "Forcing rebuild of ISO because files on ISO have been modified."
1100 einfo "Forcing rebuild of ISO because files on ISO have been modified."
1103 # support mkisofs as well as genisoimage
1104 if which mkisofs >/dev/null 2>&1; then
1106 elif which genisoimage >/dev/null 2>&1; then
1107 MKISOFS='genisoimage'
1109 log "Error: neither mkisofs nor genisoimage available - can not create ISO."
1110 eerror "Error: neither mkisofs nor genisoimage available - can not create ISO." ; eend 1
1115 if cd "$BUILD_OUTPUT" ; then
1116 if [ "$BOOT_METHOD" = "grub2" ]; then
1117 # make a 2048-byte bootsector for El Torito
1118 dd if=/dev/zero of=boot/grub/toriboot.bin bs=512 count=4 2>/dev/null
1119 # those are in 2048-byte sectors, so 1 16 matches 4 63 below
1120 echo 1 16 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -B 11 | \
1121 dd of=boot/grub/toriboot.bin conv=notrunc 2>/dev/null
1123 log "$MKISOFS -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J $BOOT_ARGS -o ${ISO_OUTPUT}/${ISO_NAME} ."
1124 "$MKISOFS" -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1125 -l -r -J $BOOT_ARGS -no-pad \
1126 -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1127 # both of these need core.img there, so it’s easier to write it here
1128 if [ "$BOOT_METHOD" = "grub2" ] || [ "$HYBRID_METHOD" = "grub2" ]; then
1129 # must be <= 30720 bytes
1130 dd if=boot/grub/core.img of="${ISO_OUTPUT}/${ISO_NAME}" \
1131 conv=notrunc bs=512 seek=4 2>/dev/null
1134 # pad the output ISO to multiples of 256 KiB for partition table support
1135 siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1136 cyls=$((siz / 512 / 32 / 16 + 1)) # C=$cyls H=16 S=32
1137 siz=$((cyls * 16 * 32 * 512)) # size after padding
1138 dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1139 of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1141 # support disabling hybrid ISO image
1142 if [ "$HYBRID_METHOD" = "disable" ] ; then\
1143 log "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1144 einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1146 # use isohybrid only on request
1147 elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
1148 if ! which isohybrid >/dev/null 2>&1 ; then
1149 bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1151 log "Creating hybrid ISO file with isohybrid method"
1152 einfo "Creating hybrid ISO file with isohybrid method"
1153 # Notes for consideration:
1154 # "-entry 4 -type 1c"
1155 # * using 4 as the partition number is supposed to help with BIOSes
1156 # that only support USB-Zip boot
1157 # * using 1c (i.e. hidden FAT32 LBA), instead of the default 0x17
1158 # (hidden NTFS, IIRC), as the partition type is sometimes needed
1159 # to get the BIOS even look at the partition created by isohybrid
1160 isohybrid "${ISO_OUTPUT}/${ISO_NAME}"
1163 # by default use our manifold boot method:
1165 # isoinfo is part of both mkisofs and genisoimage so we're good
1166 bootoff=$(isoinfo -l -i "${ISO_OUTPUT}/${ISO_NAME}" | \
1167 sed -n '/^.*\[ *\([0-9]*\)[] ].* ISOLINUX.BIN;1 *$/s//\1/p')
1168 if ! [ -r boot/grub/core.img ] ; then
1169 ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1170 elif [ "${bootoff:-0}" -lt 1 ] ; then
1171 ewarn "isolinux.bin not found on the ISO file, disabling manifold boot"
1173 log "Creating hybrid ISO file with manifold method"
1174 einfo "Creating hybrid ISO file with manifold method"
1175 if [ "$HYBRID_METHOD" = "grub2" ] ; then
1176 # 512 bytes: MBR, partition table, load GRUB 2
1177 echo 4 63 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 4:0x96 -g $cyls:16:32
1179 # read only one but 2048-byte sized (scale: << 2) sector
1180 echo $bootoff $bootoff | \
1181 mksh /usr/share/grml-live/scripts/bootilnx.mksh -A -M 4:0x96 -g $cyls:16:32 -S 2
1182 fi | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1187 # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1188 case $CLASSES in *RELEASE*)
1191 if cd $ISO_OUTPUT ; then
1192 md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1193 touch -r ${ISO_NAME} ${ISO_NAME}.md5
1194 sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1195 touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1204 if [ "$RC" = 0 ] ; then
1205 log "Finished execution of stage 'iso build' [$(date)]"
1206 einfo "Finished execution of stage 'iso build'" ; eend 0
1208 log "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1209 eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1215 # pack artifacts {{{
1216 if [ -n "$PACK_ARTIFACTS" ]; then
1217 log "Packing artifcats"
1218 einfo "Packing artifacts"
1219 [ -f "${CHROOT_ARCHIVE}" ] && rm -r "${CHROOT_ARCHIVE}"
1220 tar -c -a -f ${CHROOT_ARCHIVE} --preserve-permissions -C "$(dirname ${CHROOT_OUTPUT})" "$(basename ${CHROOT_OUTPUT})"
1225 # log build information to database if grml-live-db is installed and enabled {{{
1227 if [ -d /usr/share/grml-live-db ] ; then
1230 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1231 [ -n "$DPKG_DATABASE" ] || DPKG_DATABASE=/var/log/grml-live.db
1232 [ -n "$DPKG_DBSCRIPT" ] || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1233 [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1235 if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1236 log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1237 eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1241 # disable by default for now, not sure whether really everyone is using a local db file
1242 #if ! touch "$DPKG_DATABASE" ; then
1243 # eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1247 if ! [ -r "$DPKG_LIST" ] ; then
1248 log "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1249 ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1251 einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1252 log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1253 log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1256 if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1272 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1273 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1275 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1277 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1281 ## END OF FILE #################################################################
1282 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2