3 # Purpose: build process script for generating a (grml based) Linux Live-ISO
4 # Authors: grml-team (grml.org),
5 # (c) Michael Prokop <mika@grml.org>,
6 # (c) Thorsten Glaser <tg@mirbsd.org>
7 # Bug-Reports: see http://grml.org/bugs/
8 # License: This file is licensed under the GPL v2 or any later version.
9 ################################################################################
11 # some misc and global stuff {{{
15 # define function getfilesize before "set -e"
16 if stat --help >/dev/null 2>&1; then
17 getfilesize='stat -c %s' # GNU stat
19 getfilesize='stat -f %z' # BSD stat
23 # disable for now since it seems to cause some problems
27 GRML_LIVE_VERSION='0.16.1'
30 ADDONS_LIST_FILE='/boot/isolinux/addons_list.cfg'
33 # usage information {{{
37 $PN - build process script for generating a (grml based) Linux Live-ISO
39 Usage: $PN [options, see as follows]
41 -a <architecture> architecture; available values: i386 and amd64
42 -A ensure clean build and pack artifacts
43 -b build the ISO without updating the chroot via FAI
44 -B build the ISO without touching the chroot (skips cleanup)
45 -c <classe[s]> classes to be used for building the ISO via FAI
46 -C <configfile> configuration file for grml-live
47 -d <date> use specified date instead of build time as date of release
48 -D <configdir> use specified configuration directory instead of /etc/grml/fai
49 -F force execution without prompting
50 -g <grml_name> set the grml flavour name
51 -h display short usage information and exit
52 -i <iso_name> name of ISO
53 -I <src_directory> directory which provides files that should become
54 part of the chroot/ISO
55 -n skip generation of ISO
56 -N bootstrap (build chroot) only, do not create files for ISO
57 -o <output_directory> main output directory of the build process
59 -r <release_name> release name
60 -s <suite> Debian suite; values: etch, lenny, squeeze, sid
61 -t <template_directory> place of the templates
62 -T <tar_name> unpack chroot tar archive before starting
63 -u update existing chroot instead of rebuilding it from scratch
64 -U <username> arrange output to be owned by specified username
65 -v <version_number> specify version number of the release
66 -V increase verbosity in the build process
67 -z use ZLIB instead of LZMA/XZ compression
72 $PN -c GRMLBASE,GRML_FULL,AMD64 -o /dev/shm/grml
73 $PN -c GRMLBASE,GRML_FULL,AMD64 -i grml_0.0-1.iso -v 0.0-1
74 $PN -c GRMLBASE,GRML_FULL,AMD64 -s sid -V -r 'grml-live rocks'
76 More details: man grml-live + /usr/share/doc/grml-live/grml-live.html
77 http://grml.org/grml-live/
79 Please send your bug reports and feedback to the grml-team: http://grml.org/bugs/
83 # make sure it's possible to get usage information without being
84 # root or actually executing the script
85 if [ "$1" = '-h' -o "$1" = '--help' ] ; then
87 [ "$(id -u 2>/dev/null)" != 0 ] && echo "Please notice that this script requires root permissions."
92 # some runtime checks {{{
93 # we need root permissions for the build-process:
94 if [ "$(id -u 2>/dev/null)" != 0 ] ; then
95 echo "Error: please run this script with uid 0 (root)." >&2
99 if [ -r /var/run/fai/FAI_INSTALLATION_IN_PROGRESS ] ; then
100 echo "/usr/sbin/fai already running or was aborted before.">&2
101 echo "You may remove /var/run/fai/FAI_INSTALLATION_IN_PROGRESS and try again.">&2
106 if [ -r /var/run/fai/fai_softupdate_is_running ] ; then
107 echo "/usr/sbin/fai softupdate already running or was aborted before.">&2
108 echo "You may remove /var/run/fai/fai_softupdate_is_running and try again.">&2
113 # lsb-functions and configuration stuff {{{
114 # make sure they are not set by default
123 # don't use colors/escape sequences
124 if [ -r /lib/lsb/init-functions ] ; then
125 . /lib/lsb/init-functions
126 ! log_use_fancy_output && NOCOLORS=true
129 if [ -r /etc/grml/lsb-functions ] ; then
130 . /etc/grml/lsb-functions
132 einfo() { echo " [*] $*" ;}
133 eerror() { echo " [!] $*">&2 ;}
134 ewarn() { echo " [x] $*" ;}
136 eindent() { return 0 ;}
137 eoutdent() { return 0 ;}
140 # source main configuration file:
141 LIVE_CONF=/etc/grml/grml-live.conf
145 # umount all directories {{{
147 # make sure we don't leave any mounts - FAI doesn't remove them always
148 umount $CHROOT_OUTPUT/proc 2>/dev/null || /bin/true
149 umount $CHROOT_OUTPUT/sys 2>/dev/null || /bin/true
150 umount $CHROOT_OUTPUT/dev/pts 2>/dev/null || /bin/true
151 umount $CHROOT_OUTPUT/dev 2>/dev/null || /bin/true
153 # certain FAI versions sadly leave a ramdisk behind, so better safe than sorry
154 if [ -x /usr/lib/fai/mkramdisk ] ; then
155 /usr/lib/fai/mkramdisk -u "$(readlink -f ${CHROOT_OUTPUT}/var/lib/dpkg)" >/dev/null 2>&1 || /bin/true
158 umount "${CHROOT_OUTPUT}/grml-live/sources/" 2>/dev/null || /bin/true
159 [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
165 rm -f /var/run/fai/fai_softupdate_is_running \
166 /var/run/fai/FAI_INSTALLATION_IN_PROGRESS
167 [ -n "$SQUASHFS_STDERR" ] && rm -rf "$SQUASHFS_STDERR"
169 [ -n "$1" ] && EXIT="$1" || EXIT="1"
170 [ -n "$2" ] && eerror "$2">&2
171 if [ -n "$PACK_ARTIFACTS" ]; then
174 [ -n "${BUILD_OUTPUT}" -a -d "${BUILD_OUTPUT}" ] && rm -r "${BUILD_OUTPUT}"
175 [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && rm -r "${CHROOT_OUTPUT}"
178 if [ -n "$CHOWN_USER" ]; then
179 log "Setting ownership"
180 einfo "Setting ownership"
181 [ -n "${OUTPUT}" -a -d "${OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${OUTPUT}"
182 [ -n "${BUILD_OUTPUT}" -a -d "${BUILD_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${BUILD_OUTPUT}"
183 [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${CHROOT_OUTPUT}"
184 [ -n "${ISO_OUTPUT}" -a -d "${ISO_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${ISO_OUTPUT}"
185 [ -n "${LOG_OUTPUT}" -a -d "${LOG_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${LOG_OUTPUT}"
186 [ -n "${CHROOT_ARCHIVE}" -a -f "${CHROOT_ARCHIVE}" ] && chown -R "${CHOWN_USER}:" "${CHROOT_ARCHIVE}"
189 log "------------------------------------------------------------------------------"
192 trap bailout 1 2 3 3 6 9 14 15
196 # some important functions {{{
199 # usage: log "string to log"
200 log() { [ -n "$LOGFILE" ] && echo "$*" >> $LOGFILE ; }
202 # cut string at character number int = $1
203 # usage: cut_string 5 "1234567890" will output "12345"
205 [ -n "$2" ] || return 1
206 echo "$2" | head -c "$1"; echo -ne "\n"
209 # prepend int = $1 spaces before string = $2
210 # usage: extend_string_begin 5 "123" will output " 123"
211 extend_string_begin() {
212 [ -n "$2" ] || return 1
213 local COUNT="$(echo $2 | wc -c)"
214 local FILL="$(expr $COUNT - $1)"
215 while [ "$FILL" -gt 1 ] ; do
217 local FILL=$(expr $FILL - 1)
219 while [ "$FILL" -lt 1 ] ; do
221 local FILL=$(expr $FILL + 1)
223 echo "$2" | head -c "$1"; echo -ne "\n"
226 # append int = $1 spaces to string = $2
227 # usage: extend_string_begin 5 "123" will output "123 "
228 extend_string_end() {
229 [ -n "$2" ] || return 1
230 echo -n "$2" | head -c "$1"
231 local COUNT="$(echo $2 | wc -c)"
232 local FILL="$(expr $COUNT - $1)"
233 while [ "$FILL" -gt 1 ] ; do
235 local FILL=$(expr $FILL - 1)
237 while [ "$FILL" -lt 1 ] ; do
239 local FILL=$(expr $FILL + 1)
244 # Copy addonfile $1 from either
245 # * the chroot (via $2, the system path),
246 # * or from TEMPLATE_DIRECTORY/compat (if exists),
247 # * or from the host system (again, using $2),
248 # or warn about the missing file.
251 # * We assume that the chroot always has a "good" version of
252 # the file. Also it makes sources handling easier.
253 # * On unstable, we Recommend the Debian packages containing
254 # these files. The user can override them by putting his
255 # "better" version into the chroot.
256 # * On stable, the Debian packages are probably not available,
257 # or outdated, so we look in TEMPLATE_DIRECTORY/compat first, where
258 # our grml-live-compat package installs current file versions.
260 DEST="${BUILD_OUTPUT}/boot/$3"
261 if [ ! -d "${DEST}/" ]; then
264 if [ -e "$CHROOT_OUTPUT/$2/$1" ]; then
265 log "Copying $1 from chroot"
266 cp "$CHROOT_OUTPUT/$2/$1" "${DEST}/"
269 if [ -e "${TEMPLATE_DIRECTORY}/compat/$3/$1" ]; then
270 log "Copying $1 from grml-live-compat"
271 cp "${TEMPLATE_DIRECTORY}/compat/$3/$1" "${DEST}/"
274 if [ -e "$2/$1" ]; then
275 log "Copying $1 from system"
276 cp "$2/$1" "${DEST}/"
280 msg="Missing addon file: \"$1\""
281 ewarn "$msg" ; eend 1
282 log "copy_addon_file: $msg"
286 # read local (non-packaged) configuration {{{
287 LOCAL_CONFIG=/etc/grml/grml-live.local
288 if [ -r "$LOCAL_CONFIG" ] ; then
294 if [ -n "${GRML_LIVE_SOURCES:-}" ] ; then
295 eerror "Config variable \$GRML_LIVE_SOURCES is set. This variable has been deprecated."
296 ewarn "Please set up ${GRML_FAI_CONFIG}/config/files/etc/apt/sources.list.d/* instead."
301 # command line parsing {{{
302 while getopts "a:C:c:d:D:g:i:I:o:r:s:t:T:U:v:AbBFnNquVz" opt; do
305 A) PACK_ARTIFACTS=1 ;;
308 c) CLASSES="$OPTARG" ;;
309 C) CONFIG="$OPTARG" ;;
311 D) GRML_FAI_CONFIG="$OPTARG" ;;
312 g) GRML_NAME="$OPTARG" ;;
313 i) ISO_NAME="$OPTARG" ;;
314 I) CHROOT_INSTALL="$OPTARG" ;;
316 N) BOOTSTRAP_ONLY=1; SKIP_MKISOFS=1; SKIP_MKSQUASHFS=1 ;;
317 o) OUTPUT="$OPTARG" ;;
318 q) SKIP_MKSQUASHFS=1 ;;
319 r) RELEASENAME="$OPTARG" ;;
320 s) SUITE="$OPTARG" ;;
321 t) TEMPLATE_DIRECTORY="$OPTARG";;
322 T) UNPACK_CHROOT="$(readlink -f $OPTARG)" ;;
323 v) VERSION="$OPTARG" ;;
326 U) CHOWN_USER="$OPTARG" ;;
328 z) SQUASHFS_ZLIB=1 ;;
329 ?) echo "invalid option -$OPTARG" >&2; bailout 1 ;;
332 shift $(($OPTIND - 1)) # set ARGV to the first not parsed commandline parameter
335 # assume sane defaults (if not set already) {{{
336 [ -n "$ARCH" ] || ARCH="$(dpkg --print-architecture)"
337 [ -n "$BOOT_METHOD" ] || BOOT_METHOD='isolinux'
338 [ -n "$CLASSES" ] || CLASSES="GRMLBASE,GRML_FULL,$(echo ${ARCH} | tr 'a-z' 'A-Z')"
339 [ -n "$DATE" ] || DATE="$(date +%Y-%m-%d)"
340 [ -n "$DISTRI_INFO" ] || DISTRI_INFO='Grml - Live Linux for system administrators '
341 [ -n "$DISTRI_NAME" ] || DISTRI_NAME="grml"
342 [ -n "$DISTRI_SPLASH" ] || DISTRI_SPLASH='grml.png'
343 [ -n "$FORCE_ISO_REBUILD" ] || FORCE_ISO_REBUILD="false"
344 [ -n "$GRML_FAI_CONFIG" ] || GRML_FAI_CONFIG='/etc/grml/fai'
345 [ -n "$GRML_NAME" ] || GRML_NAME='grml'
346 [ -n "$HOSTNAME" ] || HOSTNAME='grml'
347 [ -n "$HYBRID_METHOD" ] || HYBRID_METHOD='manifold'
348 [ -n "$NFSROOT_CONF" ] || NFSROOT_CONF="${GRML_FAI_CONFIG}/make-fai-nfsroot.conf"
349 [ -n "$RELEASENAME" ] || RELEASENAME='grml-live rocks'
350 [ -n "$SQUASHFS_EXCLUDES_FILE" ] || SQUASHFS_EXCLUDES_FILE="${GRML_FAI_CONFIG}/config/grml/squashfs-excludes"
351 [ -n "$SUITE" ] || SUITE='squeeze'
352 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
353 [ -n "$USERNAME" ] || USERNAME='grml'
354 [ -n "$VERSION" ] || VERSION='0.0.1'
356 # output specific stuff, depends on $OUTPUT (iff not set):
357 [ -n "$OUTPUT" ] || OUTPUT='/grml/grml-live'
358 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
359 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
360 [ -n "$CHROOT_ARCHIVE" ] || CHROOT_ARCHIVE="$OUTPUT/$(basename $CHROOT_OUTPUT).tgz"
361 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
362 [ -n "$LOG_OUTPUT" ] || LOG_OUTPUT="$OUTPUT/grml_logs"
365 # some misc checks before executing FAI {{{
366 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
367 specify it on the command line using the -c option."
368 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
369 specify it on the command line using the -o option."
371 # trim characters that are known to cause problems inside $GRML_NAME;
372 # for example isolinux does not like '-' inside the directory name
373 [ -n "$GRML_NAME" ] && export SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
375 # export variables to have them available in fai scripts:
376 [ -n "$GRML_NAME" ] && export GRML_NAME="$GRML_NAME"
377 [ -n "$RELEASENAME" ] && export RELEASENAME="$RELEASENAME"
380 # ZERO_LOGFILE - check for backwards compatibility reasons {{{
381 # this was default behaviour until grml-live 0.9.34:
382 if [ -n "$ZERO_LOGFILE" ] ; then
383 PRESERVE_LOGFILE='' # make sure it's cleaned then
384 ewarn "Please consider disabling the \$ZERO_LOGFILE option as grml-live clears..."
385 ewarn "... the logfile $LOGFILE by default (unless \$PRESERVE_LOGFILE is set) nowadays."
390 # ask user whether the setup is ok {{{
391 if [ -z "$FORCE" ] ; then
393 echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
395 echo " FAI classes: $CLASSES"
396 [ -r "$LOCAL_CONFIG" ] && echo " Local config: /etc/grml/grml-live.local"
397 [ -n "$CONFIG" ] && echo " Configuration: $CONFIG"
398 [ -n "$GRML_FAI_CONFIG" ] && echo " Config directory: $GRML_FAI_CONFIG"
399 echo " main directory: $OUTPUT"
400 [ -n "$UNPACK_CHROOT" ] && echo " Chroot from: $UNPACK_CHROOT"
401 [ -n "$CHROOT_OUTPUT" ] && echo " Chroot target: $CHROOT_OUTPUT"
402 [ -n "$BUILD_OUTPUT" ] && echo " Build target: $BUILD_OUTPUT"
403 [ -n "$ISO_OUTPUT" ] && echo " ISO target: $ISO_OUTPUT"
404 [ -n "$GRML_NAME" ] && echo " Grml name: $GRML_NAME"
405 [ -n "$RELEASENAME" ] && echo " Release name: $RELEASENAME"
406 [ -n "$DATE" ] && echo " Build date: $DATE"
407 [ -n "$VERSION" ] && echo " Grml version: $VERSION"
408 [ -n "$SUITE" ] && echo " Debian suite: $SUITE"
409 [ -n "$ARCH" ] && echo " Architecture: $ARCH"
410 [ -n "$BOOT_METHOD" ] && echo " Boot method: $BOOT_METHOD"
411 [ -n "$HYBRID_METHOD" ] && echo " Hybrid method: $HYBRID_METHOD"
412 [ -n "$TEMPLATE_DIRECTORY" ] && echo " Template files: $TEMPLATE_DIRECTORY"
413 [ -n "$CHROOT_INSTALL" ] && echo " Install files from directory to chroot: $CHROOT_INSTALL"
414 [ -n "$BOOTID" ] && echo " Boot identifier: $BOOTID"
415 [ -n "$NO_BOOTID" ] && echo " Skipping bootid feature."
416 [ -n "$CHOWN_USER" ] && echo " Output owner: $CHOWN_USER"
417 [ -n "$DEFAULT_BOOTOPTIONS" ] && echo " Adding default bootoptions: \"$DEFAULT_BOOTOPTIONS\""
418 [ -n "$FAI_ARGS" ] && echo " Additional arguments for FAI: $FAI_ARGS"
419 [ -n "$LOGFILE" ] && echo " Logging to file: $LOGFILE"
420 [ -n "$SQUASHFS_ZLIB" ] && echo " Using ZLIB (instead of LZMA/XZ) compression."
421 [ -n "$SQUASHFS_OPTIONS" ] && echo " Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
422 [ -n "$VERBOSE" ] && echo " Using VERBOSE mode."
423 [ -n "$PACK_ARTIFACTS" ] && echo " Will prepare packed artifacts and ensure clean build."
424 [ -n "$UPDATE" ] && echo " Executing UPDATE instead of fresh installation."
425 if [ -n "$BOOTSTRAP_ONLY" ] ; then
426 echo " Bootstrapping only and not building (files for) ISO."
428 [ -n "$SKIP_MKSQUASHFS" ] && echo " Skipping creation of SQUASHFS file."
429 [ -n "$SKIP_MKISOFS" ] && echo " Skipping creation of ISO file."
430 [ -n "$BUILD_ONLY" ] && echo " Executing BUILD_ONLY instead of fresh installation or UPDATE."
431 [ -n "$BUILD_DIRTY" ] && echo " Executing BUILD_DIRTY to leave chroot untouched."
434 echo -n "Is this ok for you? [y/N] "
436 if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
437 bailout 1 "Exiting as requested."
443 # clean up before start {{{
444 if [ -n "${PACK_ARTIFACTS}" ]; then
445 echo "Wiping old artifacts"
446 [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && rm -r "${CHROOT_OUTPUT}"
447 [ -n "${BUILD_OUTPUT}" -a -d "${BUILD_OUTPUT}" ] && rm -r "${BUILD_OUTPUT}"
448 [ -n "${ISO_OUTPUT}" -a -d "${ISO_OUTPUT}" ] && rm -r "${ISO_OUTPUT}"
449 [ -n "${LOG_OUTPUT}" -a -d "${LOG_OUTPUT}" ] && rm -r "${LOG_OUTPUT}"
453 # create log file {{{
454 [ -n "$LOGFILE" ] || LOGFILE=${LOG_OUTPUT}/grml-live.log
455 mkdir -p $(dirname "${LOGFILE}")
457 chown root:adm $LOGFILE
461 # clean/zero/remove logfiles {{{
463 if [ -n "$PRESERVE_LOGFILE" ] ; then
464 echo "Preserving logfile $LOGFILE as requested via \$PRESERVE_LOGFILE"
466 # make sure it is empty (as it is e.g. appended to grml-live-db)
470 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
471 if [ -d /var/log/fai/"$HOSTNAME" ] ; then
472 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
473 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
474 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
475 rm -f /var/log/fai/"$HOSTNAME"/last \
476 /var/log/fai/"$HOSTNAME"/last-dirinstall \
477 /var/log/fai/"$HOSTNAME"/last-softupdate
482 # source config and startup {{{
483 if [ -n "$CONFIG" ] ; then
484 if ! [ -f "$CONFIG" ] ; then
485 log "Error: $CONFIG could not be read. Exiting. [$(date)]"
486 eerror "Error: $CONFIG could not be read. Exiting." ; eend 1
489 log "Sourcing $CONFIG"
494 start_seconds=$(cut -d . -f 1 /proc/uptime)
495 log "------------------------------------------------------------------------------"
496 log "Starting grml-live [${GRML_LIVE_VERSION}] run on $(date)"
497 if [ -n "$LOCAL_CONFIG" ]; then
498 log "Using local config file: $LOCAL_CONFIG"
500 log "Executed grml-live command line:"
503 einfo "Logging actions to logfile $LOGFILE"
507 if [ -n "${UNPACK_CHROOT}" ]; then
508 log "Unpacking chroot from ${UNPACK_CHROOT}"
509 einfo "Unpacking chroot from ${UNPACK_CHROOT}"
510 [ -d "$CHROOT_OUTPUT" ] || mkdir -p "${CHROOT_OUTPUT}"
511 tar -xf "${UNPACK_CHROOT}" -C "${CHROOT_OUTPUT}/" --strip-components 1 | RC=$?
513 if [ "$RC" != 0 ] ; then
521 # cleanup CHROOT_ARCHIVE now {{{
522 if [ -n "${PACK_ARTIFACTS}" ]; then
523 # can't do this earlier, as UNPACK_CHROOT might point to CHROOT_ARCHIVE
524 [ -n "${CHROOT_ARCHIVE}" -a -f "${CHROOT_ARCHIVE}" ] && rm "${CHROOT_ARCHIVE}"
528 # on-the-fly configuration {{{
529 if [ -n "$FAI_DEBOOTSTRAP" ] ; then
530 sed "s#^FAI_DEBOOTSTRAP=.*#FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"#" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
533 # does this suck? YES!
534 # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
536 unstable) SUITE='sid' ; CLASSES="DEBIAN_UNSTABLE,$CLASSES" ;;
537 *) CLASSES="DEBIAN_$(echo $SUITE | tr 'a-z' 'A-Z'),$CLASSES";;
539 export SUITE # make sure it's available in FAI scripts
541 for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" "$NFSROOT_CONF" ; do
542 if [ -n "$file" ] ; then
543 sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
547 # validate whether the specified architecture class matches the
548 # architecture (option), otherwise installation of kernel will fail
549 if echo $CLASSES | grep -qi i386 ; then
550 if ! [[ "$ARCH" == "i386" ]] ; then
551 log "Error: You specified the I386 class but are trying to build something else (AMD64?)."
552 eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
553 eerror "Tip: Either invoke grml-live with '-a i386' or adjust the architecture class. Exiting."
557 elif echo $CLASSES | grep -qi amd64 ; then
558 if ! [[ "$ARCH" == "amd64" ]] ; then
559 log "Error: You specified the AMD64 class but are trying to build something else (I386?)."
560 eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
561 eerror "Tip: Either invoke grml-live with '-a amd64' or adjust the architecture class. Exiting."
567 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
568 sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
570 sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
574 # CHROOT_OUTPUT - execute FAI {{{
575 if [ -n "$BUILD_DIRTY" ]; then
576 log "Skipping stage 'fai' as requested via option -B"
577 ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
579 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
581 # provide inform fai about the ISO we build
582 [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
583 echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
584 [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
585 [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
587 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
588 FAI_ACTION=softupdate
590 FAI_ACTION=dirinstall
593 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
594 if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
595 log "Error: does not look like you have a working chroot. Updating/building not possible."
596 eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
602 if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
603 log "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
604 ewarn "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
606 mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
608 if [ -n "${MIRROR_DIRECTORY}" ] ; then
609 mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
610 mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
613 mkdir -p "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
614 mount --bind "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
616 # tell dpkg to use "unsafe io" during the build
617 [ -d "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d" ] || mkdir -p "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d"
618 echo force-unsafe-io > "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
620 log "Executed FAI command line:"
621 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"
622 BUILD_ONLY="$BUILD_ONLY" BOOTSTRAP_ONLY="$BOOTSTRAP_ONLY" fai $VERBOSE \
623 -C "$GRML_FAI_CONFIG" -s "file:///$GRML_FAI_CONFIG/config" -c"$CLASSES" \
624 -u "$HOSTNAME" "$FAI_ACTION" "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
625 RC="$PIPESTATUS" # notice: bash-only
627 rm -f "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
629 FORCE_ISO_REBUILD=true
631 if [ "$RC" != 0 ] ; then
632 log "Error: critical error while executing fai [exit code ${RC}]. Exiting."
633 eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
636 einfo "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
637 log "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
638 echo "$GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]" > $CHROOT_OUTPUT/etc/grml_version
639 chmod 644 $CHROOT_OUTPUT/etc/grml_version
640 einfo "Rebuilding initramfs"
641 # make sure new /etc/grml_version reaches initramfs, iterate over all
642 # present kernel versions (note: we can't really handle more than one
643 # kernel version anyway right now)
644 # chroot $CHROOT_OUTPUT update-initramfs -u -t => might break when using kernel-package :(
645 for initrd in "$(basename $CHROOT_OUTPUT/boot/vmlinuz-*)" ; do
646 if ! chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -c ; then
647 einfo "Creating fresh initrd did not work, trying update instead:"
648 log "Creating fresh initrd did not work, trying update instead:"
649 chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -u
655 # move fai logs into grml_logs directory
656 mkdir -p "$LOG_OUTPUT"/fai/
657 cp -r "$CHROOT_OUTPUT"/var/log/fai/"$HOSTNAME"/last/* "$LOG_OUTPUT"/fai/
658 rm -rf "$CHROOT_OUTPUT"/var/log/fai
659 # copy fai package list
660 cp "$CHROOT_OUTPUT"/var/log/install_packages.list "$LOG_OUTPUT"/fai/
662 chown root:adm "$LOG_OUTPUT"/fai/*
663 chmod 664 "$LOG_OUTPUT"/fai/*
667 # notice: 'fai dirinstall' does not seem to exit appropriate, so:
669 CHECKLOG="$LOG_OUTPUT"/fai/
670 if [ -r "$CHECKLOG/software.log" ] ; then
671 # 1 errors during executing of commands
672 grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
673 grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
674 grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
675 grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
676 grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
679 if [ -r "$CHECKLOG/shell.log" ] ; then
680 grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=6
683 if [ -n "$ERROR" ] ; then
684 log "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
685 eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
686 eerror "Note: check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
690 log "Finished execution of stage 'fai dirinstall' [$(date)]"
691 einfo "Finished execution of stage 'fai dirinstall'"
697 # package validator {{{
698 CHECKLOG=/var/log/fai/$HOSTNAME/last
700 if [ -r "$CHECKLOG/package_errors.log" ] && grep -q '[a-z]' "$CHECKLOG/package_errors.log" ; then
702 if [ -n "$EXIT_ON_MISSING_PACKAGES" -a -z "$BUILD_DIRTY" ] ; then
703 eerror "The following packages were requested for installation but could not be processed:"
704 cat $CHECKLOG/package_errors.log
705 eerror "... exiting as requested via \$EXIT_ON_MISSING_PACKAGES."
709 ewarn "The following packages were requested for installation but could not be processed:"
710 cat $CHECKLOG/package_errors.log
716 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
717 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
718 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
721 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
722 if [ -n "$BOOTSTRAP_ONLY" ] ; then
723 log "Skipping stage 'boot' as building with bootstrap only."
724 ewarn "Skipping stage 'boot' as building with bootstrap only." ; eend 0
726 if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
727 log "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already."
728 ewarn "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already." ; eend 0
731 [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
732 [ -d "$BUILD_OUTPUT"/boot/"${SHORT_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
734 # if we don't have an initrd we a) can't boot and b) there was an error
735 # during build, so check for the file:
736 INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
737 if [ -n "$INITRD" ] ; then
738 cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.gz
739 find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
741 log "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
742 eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
746 KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
747 if [ -n "$KERNEL_IMAGE" ] ; then
748 cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/linux26
750 log "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
751 eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
755 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
756 if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
757 log "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
758 eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
762 # copy _required_ isolinux files
763 for file in ifcpu64.c32 isolinux.bin vesamenu.c32; do
764 copy_addon_file "${file}" /usr/lib/syslinux isolinux
767 # *always* copy files to output directory so the variables
768 # get adjusted according to the build.
769 cp ${TEMPLATE_DIRECTORY}/boot/isolinux/* "$BUILD_OUTPUT"/boot/isolinux/
771 if [ -n "$NO_ADDONS" ] ; then
772 log "Skipping installation of boot addons as requested via \$NO_ADDONS."
773 einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
775 if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
776 log "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
777 ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
779 # copy addons from system packages or grml-live-compat
780 copy_addon_file ipxe.lkrn /usr/lib/ipxe addons
781 copy_addon_file pci.ids /usr/share/misc addons
782 copy_addon_file memtest86+.bin /boot addons
783 for file in memdisk chain.c32 hdt.c32 menu.c32; do
784 copy_addon_file "${file}" /usr/lib/syslinux addons
787 # make memtest filename FAT16/8.3 compatible
788 mv "${BUILD_OUTPUT}/boot/addons/memtest86+.bin" \
789 "${BUILD_OUTPUT}/boot/addons/memtest"
791 # copy only files so we can handle bsd4grml on its own
792 for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
793 test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
796 if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
797 log "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
798 einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
800 if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
801 cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
803 log "Missing addon file: bsd4grml"
804 ewarn "Missing addon file: bsd4grml" ; eend 0
808 fi # no "$TEMPLATE_DIRECTORY"/boot/addons
811 if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
812 mkdir -p "${BUILD_OUTPUT}/boot/grub"
814 cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
816 if [ -e ${TEMPLATE_DIRECTORY}/compat/grub/linux.mod ]; then
817 cp "${TEMPLATE_DIRECTORY}"/compat/grub/* "${BUILD_OUTPUT}"/boot/grub/
819 if ! which "grub-mkimage" >/dev/null 2>&1 ; then
820 log "grub-mkimage not found, skipping Grub step therefore." ; eend 0
821 ewarn "grub-mkimage not found, skipping Grub step therefore."
822 ewarn "Please install grub-pc-bin or grub-common >= 1.98+20100804-14." ; eend 0
823 elif ! grub-mkimage --help | grep -q -- --format ; then
824 log "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore." ; eend 0
825 ewarn "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore."
826 ewarn "Please install grub-common >= 1.98+20100804-14 or grub-pc-bin." ; eend 0
828 # copy system grub files if grml-live-compat is not installed
829 cp -a /usr/lib/grub/*-pc/*.mod "${BUILD_OUTPUT}"/boot/grub/
830 cp -a /usr/lib/grub/*-pc/*.o "${BUILD_OUTPUT}"/boot/grub/
831 cp -a /usr/lib/grub/*-pc/*.lst "${BUILD_OUTPUT}"/boot/grub/
832 cp -a /usr/share/grub/ascii.pf2 "${BUILD_OUTPUT}"/boot/grub/
833 grub-mkimage -d /usr/lib/grub/*-pc -o \
834 "${BUILD_OUTPUT}/boot/grub/core.img" biosdisk iso9660 --format=i386-pc
838 if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
839 log "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
840 eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
844 [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
845 cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
847 # adjust boot splash information:
848 RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
849 RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
850 RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
852 if [ -r "$BUILD_OUTPUT"/GRML/grml-version ] ; then
853 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
854 sed -i "s/%DATE%/$DATE/" "$BUILD_OUTPUT"/GRML/grml-version
857 # make sure the squashfs filename is set accordingly:
858 SQUASHFS_NAME="$GRML_NAME.squashfs"
860 if [ -n "$NO_BOOTID" ] ; then
861 log 'Skipping bootid feature as requested via $NO_BOOTID.'
862 einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
864 [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
865 [ -d "$BUILD_OUTPUT"/conf ] || mkdir "$BUILD_OUTPUT"/conf
866 einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
867 log "Generating /conf/bootid.txt with entry ${BOOTID}."
868 echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
872 # adjust all variables in the templates with the according distribution information
873 for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
874 "${BUILD_OUTPUT}"/boot/grub/* ; do
875 if [ -r "${file}" ] ; then
876 sed -i "s/%ARCH%/$ARCH/g" "${file}"
877 sed -i "s/%DATE%/$DATE/g" "${file}"
878 sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g" "${file}"
879 sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g" "${file}"
880 sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g" "${file}"
881 sed -i "s/%GRML_NAME%/$GRML_NAME/g" "${file}"
882 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g" "${file}"
883 sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g" "${file}"
884 sed -i "s/%SHORT_NAME%/$SHORT_NAME/g" "${file}"
885 sed -i "s/%VERSION%/$VERSION/g" "${file}"
887 [ -n "$DEFAULT_BOOTOPTIONS" ] && sed -i "s/ boot=live/ boot=live $DEFAULT_BOOTOPTIONS/" "${file}"
889 if [ -n "$NO_BOOTID" ] ; then
890 sed -i "s/ bootid=%BOOTID%//g" "${file}" # drop bootid bootoption
892 sed -i "s/%BOOTID%/$BOOTID/g" "${file}" # adjust bootid=... argument
897 # adjust bootsplash accordingly but make sure the string has the according lenght
898 SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
899 SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
900 for file in f4 f5 ; do
901 if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
902 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
903 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
907 # generate addon list
908 rm -f "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
909 for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
910 include_name=$(basename "$name")
911 echo "include $include_name" >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
914 if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
915 log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
916 echo "include grmlmain.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
917 echo "include default.cfg" > "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
918 echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
919 echo "include grml.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
921 for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
922 echo "include $(basename $f)" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
925 echo "include options.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
926 if [ ! -n "$NO_ADDONS" ] ; then
927 echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
929 echo "include isoprompt.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
930 echo "include hd.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
931 echo "include hidden.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
932 else # assume we are building a custom distribution:
933 log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
934 einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
935 if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
936 log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
938 einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
942 log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
943 echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
944 [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
948 # use old style console based isolinux method only if requested:
949 if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
950 log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
951 einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
952 if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
953 einfo "include for console.cfg already found, nothing to do."
956 log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
957 einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
958 echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
962 log 'Using graphical boot menu.'
963 if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
964 log "include for vesamenu.cfg already found, nothing to do."
966 log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
967 echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
971 if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
972 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
975 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
976 if ! [ -r "$DPKG_LIST" ] ; then
977 ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
979 einfo "Storing package list information as /GRML/${GRML_NAME}-packages.txt on ISO."
980 cp "$DPKG_LIST" "${BUILD_OUTPUT}/GRML/${GRML_NAME}-packages.txt"
984 # autostart for Windows:
985 if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
986 cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
989 FORCE_ISO_REBUILD=true
990 einfo "Finished execution of stage 'boot'" ; eend 0
994 log 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
995 eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
999 # support installation of local files into the chroot/ISO
1000 if [ -n "$CHROOT_INSTALL" ] ; then
1001 if ! [ -d "$CHROOT_INSTALL" ] ; then
1002 log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1003 ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1005 log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1006 einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1007 rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
1009 einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
1010 FORCE_ISO_REBUILD=true
1014 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
1015 log "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
1016 ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
1017 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
1018 log "Skipping stage 'squashfs' as requested via option -q or -N"
1019 ewarn "Skipping stage 'squashfs' as requested via option -q or -N" ; eend 0
1021 [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
1022 # make sure we don't leave (even an empty) base.tgz:
1023 [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
1025 # if unconfigured default to squashfs-tools' mksquashfs binary
1026 if [ -z "$SQUASHFS_BINARY" ] ; then
1027 SQUASHFS_BINARY='mksquashfs'
1030 if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
1031 log "Using mksquashfs binary ${SQUASHFS_BINARY}"
1032 einfo "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
1034 log "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
1035 eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
1039 # use sane defaults if $SQUASHFS_OPTIONS isn't set
1040 if [ -z "$SQUASHFS_OPTIONS" ] ; then
1041 # use blocksize 256k as this gives best result with regards to time + compression
1042 SQUASHFS_OPTIONS="-b 256k"
1044 # set lzma/xz compression by default, unless -z option has been specified on command line
1045 if [ -z "$SQUASHFS_ZLIB" ] ; then
1046 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp xz"
1048 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp gzip"
1052 # support exclusion of files via exclude-file:
1053 if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
1054 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE -wildcards"
1057 # get rid of unnecessary files when building grml-small for final release:
1058 if echo "$CLASSES" | grep -q GRML_SMALL ; then
1059 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
1063 SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
1065 # informational stuff
1066 [ -n "$SQUASHFS_OPTIONS" ] && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
1067 [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
1068 einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
1070 log "$SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS"
1072 if $SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
1073 -noappend $SQUASHFS_OPTIONS 2>"${SQUASHFS_STDERR}" ; then
1074 echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
1075 log "Finished execution of stage 'squashfs' [$(date)]"
1076 einfo "Finished execution of stage 'squashfs'" ; eend 0
1078 log "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1079 log "$(cat $SQUASHFS_STDERR)"
1080 eerror "Error: there was a critical error executing stage 'squashfs':"
1081 cat "${SQUASHFS_STDERR}"
1086 FORCE_ISO_REBUILD=true
1089 # create md5sum file:
1090 if [ -z "$BOOTSTRAP_ONLY" ] ; then
1091 ( cd $BUILD_OUTPUT/GRML &&
1092 find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1096 # ISO_OUTPUT - mkisofs {{{
1097 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1098 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1100 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1101 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1102 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1103 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1106 # Just until http://bts.grml.org/grml/issue945 has been resolved.
1107 # HYBRID_METHOD defaults to manifold, so make sure the default works OOTB.
1108 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1109 log "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1110 ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1111 HYBRID_METHOD='grub2'
1115 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ] ; then
1116 log "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1117 ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1118 elif [ -n "$SKIP_MKISOFS" ] ; then
1119 log "Skipping stage 'iso build' as requested via option -n or -N"
1120 ewarn "Skipping stage 'iso build' as requested via option -n or -N" ; eend 0
1122 mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1124 if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1125 log "Forcing rebuild of ISO because files on ISO have been modified."
1126 einfo "Forcing rebuild of ISO because files on ISO have been modified."
1129 # support mkisofs as well as genisoimage
1130 if which mkisofs >/dev/null 2>&1; then
1132 elif which genisoimage >/dev/null 2>&1; then
1133 MKISOFS='genisoimage'
1135 log "Error: neither mkisofs nor genisoimage available - can not create ISO."
1136 eerror "Error: neither mkisofs nor genisoimage available - can not create ISO." ; eend 1
1141 if cd "$BUILD_OUTPUT" ; then
1142 if [ "$BOOT_METHOD" = "grub2" ]; then
1143 # make a 2048-byte bootsector for El Torito
1144 dd if=/dev/zero of=boot/grub/toriboot.bin bs=512 count=4 2>/dev/null
1145 # those are in 2048-byte sectors, so 1 16 matches 4 63 below
1146 echo 1 16 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -B 11 | \
1147 dd of=boot/grub/toriboot.bin conv=notrunc 2>/dev/null
1149 log "$MKISOFS -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J $BOOT_ARGS -o ${ISO_OUTPUT}/${ISO_NAME} ."
1150 "$MKISOFS" -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1151 -l -r -J $BOOT_ARGS -no-pad \
1152 -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1153 # both of these need core.img there, so it’s easier to write it here
1154 if [ "$BOOT_METHOD" = "grub2" ] || [ "$HYBRID_METHOD" = "grub2" ]; then
1155 # must be <= 30720 bytes
1156 dd if=boot/grub/core.img of="${ISO_OUTPUT}/${ISO_NAME}" \
1157 conv=notrunc bs=512 seek=4 2>/dev/null
1160 # pad the output ISO to multiples of 256 KiB for partition table support
1161 siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1162 cyls=$((siz / 512 / 32 / 16 + 1)) # C=$cyls H=16 S=32
1163 siz=$((cyls * 16 * 32 * 512)) # size after padding
1164 dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1165 of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1167 # support disabling hybrid ISO image
1168 if [ "$HYBRID_METHOD" = "disable" ] ; then\
1169 log "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1170 einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1172 # use isohybrid only on request
1173 elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
1174 if ! which isohybrid >/dev/null 2>&1 ; then
1175 bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1177 log "Creating hybrid ISO file with isohybrid method"
1178 einfo "Creating hybrid ISO file with isohybrid method"
1179 # Notes for consideration:
1180 # "-entry 4 -type 1c"
1181 # * using 4 as the partition number is supposed to help with BIOSes
1182 # that only support USB-Zip boot
1183 # * using 1c (i.e. hidden FAT32 LBA), instead of the default 0x17
1184 # (hidden NTFS, IIRC), as the partition type is sometimes needed
1185 # to get the BIOS even look at the partition created by isohybrid
1186 isohybrid "${ISO_OUTPUT}/${ISO_NAME}"
1189 # by default use our manifold boot method:
1191 # isoinfo is part of both mkisofs and genisoimage so we're good
1192 bootoff=$(isoinfo -l -i "${ISO_OUTPUT}/${ISO_NAME}" | \
1193 sed -n '/^.*\[ *\([0-9]*\)[] ].* ISOLINUX.BIN;1 *$/s//\1/p')
1194 if ! [ -r boot/grub/core.img ] ; then
1195 ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1196 elif [ "${bootoff:-0}" -lt 1 ] ; then
1197 ewarn "isolinux.bin not found on the ISO file, disabling manifold boot"
1199 log "Creating hybrid ISO file with manifold method"
1200 einfo "Creating hybrid ISO file with manifold method"
1201 if [ "$HYBRID_METHOD" = "grub2" ] ; then
1202 # 512 bytes: MBR, partition table, load GRUB 2
1203 echo 4 63 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 4:0x96 -g $cyls:16:32
1205 # read only one but 2048-byte sized (scale: << 2) sector
1206 echo $bootoff $bootoff | \
1207 mksh /usr/share/grml-live/scripts/bootilnx.mksh -A -M 4:0x96 -g $cyls:16:32 -S 2
1208 fi | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1213 # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1214 case $CLASSES in *RELEASE*)
1217 if cd $ISO_OUTPUT ; then
1218 md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1219 touch -r ${ISO_NAME} ${ISO_NAME}.md5
1220 sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1221 touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1230 if [ "$RC" = 0 ] ; then
1231 log "Finished execution of stage 'iso build' [$(date)]"
1232 einfo "Finished execution of stage 'iso build'" ; eend 0
1234 log "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1235 eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1241 # pack artifacts {{{
1242 if [ -n "$PACK_ARTIFACTS" ]; then
1243 log "Packing artifcats"
1244 einfo "Packing artifacts"
1245 [ -f "${CHROOT_ARCHIVE}" ] && rm -r "${CHROOT_ARCHIVE}"
1246 tar -c -a -f ${CHROOT_ARCHIVE} --preserve-permissions -C "$(dirname ${CHROOT_OUTPUT})" "$(basename ${CHROOT_OUTPUT})"
1251 # log build information to database if grml-live-db is installed and enabled {{{
1253 if [ -d /usr/share/grml-live-db ] ; then
1256 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1257 [ -n "$DPKG_DATABASE" ] || DPKG_DATABASE=/var/log/grml-live.db
1258 [ -n "$DPKG_DBSCRIPT" ] || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1259 [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1261 if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1262 log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1263 eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1267 # disable by default for now, not sure whether really everyone is using a local db file
1268 #if ! touch "$DPKG_DATABASE" ; then
1269 # eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1273 if ! [ -r "$DPKG_LIST" ] ; then
1274 log "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1275 ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1277 einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1278 log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1279 log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1282 if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1298 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1299 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1301 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1303 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1307 ## END OF FILE #################################################################
1308 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2