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_MEDIUM,I386 -o /dev/shm/grml
72 $PN -c GRMLBASE,GRML_SMALL,REMOVE_DOCS,I386 -g grml-small -v 1.0
73 $PN -c GRMLBASE,GRML_FULL,I386 -i grml_0.0-1.iso -v 0.0-1
74 $PN -c GRMLBASE,GRML_FULL,I386 -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
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 "${CHROOT_ARCHIVE}" -a -d "${CHROOT_ARCHIVE}" ] && chown -R "${CHOWN_USER}:" "${CHROOT_ARCHIVE}"
178 [ -n "${ISO_OUTPUT}" -a -d "${ISO_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${ISO_OUTPUT}"
179 [ -n "${LOG_OUTPUT}" -a -d "${LOG_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${LOG_OUTPUT}"
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
288 # command line parsing {{{
289 while getopts "a:C:c:d:D:g:i:I:o:r:s:t:U:v:AbBFnNquVz" opt; do
292 A) PACK_ARTIFACTS=1 ;;
295 c) CLASSES="$OPTARG" ;;
296 C) CONFIG="$OPTARG" ;;
298 D) GRML_FAI_CONFIG="$OPTARG" ;;
299 g) GRML_NAME="$OPTARG" ;;
300 i) ISO_NAME="$OPTARG" ;;
301 I) CHROOT_INSTALL="$OPTARG" ;;
303 N) BOOTSTRAP_ONLY=1; SKIP_MKISOFS=1; SKIP_MKSQUASHFS=1 ;;
304 o) OUTPUT="$OPTARG" ;;
305 q) SKIP_MKSQUASHFS=1 ;;
306 r) RELEASENAME="$OPTARG" ;;
307 s) SUITE="$OPTARG" ;;
308 t) TEMPLATE_DIRECTORY="$OPTARG";;
309 v) VERSION="$OPTARG" ;;
312 U) CHOWN_USER="$OPTARG" ;;
314 z) SQUASHFS_ZLIB=1 ;;
315 ?) echo "invalid option -$OPTARG" >&2; bailout 1 ;;
318 shift $(($OPTIND - 1)) # set ARGV to the first not parsed commandline parameter
321 # assume sane defaults (if not set already) {{{
322 [ -n "$ARCH" ] || ARCH="$(dpkg --print-architecture)"
323 [ -n "$BOOT_METHOD" ] || BOOT_METHOD='isolinux'
324 [ -n "$CLASSES" ] || CLASSES="GRMLBASE,GRML_MEDIUM,I386"
325 [ -n "$DATE" ] || DATE="$(date +%Y-%m-%d)"
326 [ -n "$DISTRI_INFO" ] || DISTRI_INFO='Grml - Live Linux for system administrators '
327 [ -n "$DISTRI_NAME" ] || DISTRI_NAME="grml"
328 [ -n "$DISTRI_SPLASH" ] || DISTRI_SPLASH='grml.png'
329 [ -n "$FORCE_ISO_REBUILD" ] || FORCE_ISO_REBUILD="false"
330 [ -n "$GRML_FAI_CONFIG" ] || GRML_FAI_CONFIG='/etc/grml/fai'
331 [ -n "$GRML_NAME" ] || GRML_NAME='grml'
332 [ -n "$HOSTNAME" ] || HOSTNAME='grml'
333 [ -n "$HYBRID_METHOD" ] || HYBRID_METHOD='manifold'
334 [ -n "$NFSROOT_CONF" ] || NFSROOT_CONF="${GRML_FAI_CONFIG}/make-fai-nfsroot.conf"
335 [ -n "$RELEASENAME" ] || RELEASENAME='grml-live rocks'
336 [ -n "$SOURCES_LIST_OUTPUT" ] || SOURCES_LIST_OUTPUT="${GRML_FAI_CONFIG}/config/files/etc/apt/sources.list/GRML_LIVE_SOURCES_LIST"
337 [ -n "$SQUASHFS_EXCLUDES_FILE" ] || SQUASHFS_EXCLUDES_FILE="${GRML_FAI_CONFIG}/config/grml/squashfs-excludes"
338 [ -n "$SUITE" ] || SUITE='squeeze'
339 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
340 [ -n "$USERNAME" ] || USERNAME='grml'
341 [ -n "$VERSION" ] || VERSION='0.0.1'
343 # output specific stuff, depends on $OUTPUT (iff not set):
344 [ -n "$OUTPUT" ] || OUTPUT='/grml/grml-live'
345 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
346 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
347 [ -n "$CHROOT_ARCHIVE" ] || CHROOT_ARCHIVE="$OUTPUT/$(basename $CHROOT_OUTPUT).tgz"
348 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
349 [ -n "$LOG_OUTPUT" ] || LOG_OUTPUT="$OUTPUT/grml_logs"
352 # some misc checks before executing FAI {{{
353 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
354 specify it on the command line using the -c option."
355 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
356 specify it on the command line using the -o option."
358 # trim characters that are known to cause problems inside $GRML_NAME;
359 # for example isolinux does not like '-' inside the directory name
360 [ -n "$GRML_NAME" ] && export SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
362 # export variables to have them available in fai scripts:
363 [ -n "$GRML_NAME" ] && export GRML_NAME="$GRML_NAME"
364 [ -n "$RELEASENAME" ] && export RELEASENAME="$RELEASENAME"
367 # ZERO_LOGFILE - check for backwards compatibility reasons {{{
368 # this was default behaviour until grml-live 0.9.34:
369 if [ -n "$ZERO_LOGFILE" ] ; then
370 PRESERVE_LOGFILE='' # make sure it's cleaned then
371 ewarn "Please consider disabling the \$ZERO_LOGFILE option as grml-live clears..."
372 ewarn "... the logfile $LOGFILE by default (unless \$PRESERVE_LOGFILE is set) nowadays."
377 # ask user whether the setup is ok {{{
378 if [ -z "$FORCE" ] ; then
380 echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
382 echo " FAI classes: $CLASSES"
383 [ -r "$LOCAL_CONFIG" ] && echo " Local config: /etc/grml/grml-live.local"
384 [ -n "$CONFIG" ] && echo " Configuration: $CONFIG"
385 [ -n "$GRML_FAI_CONFIG" ] && echo " Config directory: $GRML_FAI_CONFIG"
386 echo " main directory: $OUTPUT"
387 [ -n "$CHROOT_OUTPUT" ] && echo " Chroot target: $CHROOT_OUTPUT"
388 [ -n "$BUILD_OUTPUT" ] && echo " Build target: $BUILD_OUTPUT"
389 [ -n "$ISO_OUTPUT" ] && echo " ISO target: $ISO_OUTPUT"
390 [ -n "$GRML_NAME" ] && echo " Grml name: $GRML_NAME"
391 [ -n "$RELEASENAME" ] && echo " Release name: $RELEASENAME"
392 [ -n "$DATE" ] && echo " Build date: $DATE"
393 [ -n "$VERSION" ] && echo " Grml version: $VERSION"
394 [ -n "$SUITE" ] && echo " Debian suite: $SUITE"
395 [ -n "$ARCH" ] && echo " Architecture: $ARCH"
396 [ -n "$BOOT_METHOD" ] && echo " Boot method: $BOOT_METHOD"
397 [ -n "$HYBRID_METHOD" ] && echo " Hybrid method: $HYBRID_METHOD"
398 [ -n "$TEMPLATE_DIRECTORY" ] && echo " Template files: $TEMPLATE_DIRECTORY"
399 [ -n "$CHROOT_INSTALL" ] && echo " Install files from directory to chroot: $CHROOT_INSTALL"
400 [ -n "$BOOTID" ] && echo " Boot identifier: $BOOTID"
401 [ -n "$NO_BOOTID" ] && echo " Skipping bootid feature."
402 [ -n "$CHOWN_USER" ] && echo " Output owner: $CHOWN_USER"
403 [ -n "$DEFAULT_BOOTOPTIONS" ] && echo " Adding default bootoptions: \"$DEFAULT_BOOTOPTIONS\""
404 [ -n "$FAI_ARGS" ] && echo " Additional arguments for FAI: $FAI_ARGS"
405 [ -n "$LOGFILE" ] && echo " Logging to file: $LOGFILE"
406 [ -n "$SQUASHFS_ZLIB" ] && echo " Using ZLIB (instead of LZMA/XZ) compression."
407 [ -n "$SQUASHFS_OPTIONS" ] && echo " Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
408 [ -n "$VERBOSE" ] && echo " Using VERBOSE mode."
409 [ -n "$PACK_ARTIFACTS" ] && echo " Will prepare packed artifacts and ensure clean build."
410 [ -n "$UPDATE" ] && echo " Executing UPDATE instead of fresh installation."
411 if [ -n "$BOOTSTRAP_ONLY" ] ; then
412 echo " Bootstrapping only and not building (files for) ISO."
414 [ -n "$SKIP_MKSQUASHFS" ] && echo " Skipping creation of SQUASHFS file."
415 [ -n "$SKIP_MKISOFS" ] && echo " Skipping creation of ISO file."
416 [ -n "$BUILD_ONLY" ] && echo " Executing BUILD_ONLY instead of fresh installation or UPDATE."
417 [ -n "$BUILD_DIRTY" ] && echo " Executing BUILD_DIRTY to leave chroot untouched."
420 echo -n "Is this ok for you? [y/N] "
422 if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
423 bailout 1 "Exiting as requested."
429 # clean up before start {{{
430 if [ -n "${PACK_ARTIFACTS}" ]; then
431 echo "Wiping old artifacts"
432 [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && rm -r "${CHROOT_OUTPUT}"
433 [ -n "${CHROOT_ARCHIVE}" -a -d "${CHROOT_ARCHIVE}" ] && rm -r "${CHROOT_ARCHIVE}"
434 [ -n "${BUILD_OUTPUT}" -a -d "${BUILD_OUTPUT}" ] && rm -r "${BUILD_OUTPUT}"
435 [ -n "${ISO_OUTPUT}" -a -d "${ISO_OUTPUT}" ] && rm -r "${ISO_OUTPUT}"
436 [ -n "${LOG_OUTPUT}" -a -d "${LOG_OUTPUT}" ] && rm -r "${LOG_OUTPUT}"
440 # create log file {{{
441 [ -n "$LOGFILE" ] || LOGFILE=${LOG_OUTPUT}/grml-live.log
442 mkdir -p $(dirname "${LOGFILE}")
444 chown root:adm $LOGFILE
448 # clean/zero/remove logfiles {{{
450 if [ -n "$PRESERVE_LOGFILE" ] ; then
451 echo "Preserving logfile $LOGFILE as requested via \$PRESERVE_LOGFILE"
453 # make sure it is empty (as it is e.g. appended to grml-live-db)
457 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
458 if [ -d /var/log/fai/"$HOSTNAME" ] ; then
459 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
460 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
461 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
462 rm -f /var/log/fai/"$HOSTNAME"/last \
463 /var/log/fai/"$HOSTNAME"/last-dirinstall \
464 /var/log/fai/"$HOSTNAME"/last-softupdate
469 # source config and startup {{{
470 if [ -n "$CONFIG" ] ; then
471 if ! [ -f "$CONFIG" ] ; then
472 log "Error: $CONFIG could not be read. Exiting. [$(date)]"
473 eerror "Error: $CONFIG could not be read. Exiting." ; eend 1
476 log "Sourcing $CONFIG"
481 start_seconds=$(cut -d . -f 1 /proc/uptime)
482 log "------------------------------------------------------------------------------"
483 log "Starting grml-live [${GRML_LIVE_VERSION}] run on $(date)"
484 if [ -n "$LOCAL_CONFIG" ]; then
485 log "Using local config file: $LOCAL_CONFIG"
487 log "Executed grml-live command line:"
490 einfo "Logging actions to logfile $LOGFILE"
493 # on-the-fly configuration {{{
494 mkdir -p "$(dirname $SOURCES_LIST_OUTPUT)" # might not be present in -D config space
496 cat > "$SOURCES_LIST_OUTPUT" << EOF
497 # NOTE: This file is *NOT* meant for manual customisation! This file is
498 # installed temporarily only by grml-live and will be overriden in the
499 # installation and configuration process then.
502 if [ -n "$MIRROR_DIRECTORY" ] ; then
503 if ! [ -d "$MIRROR_DIRECTORY/debian" ] ; then
504 log "Error: $MIRROR_DIRECTORY/debian does not seem to exist. Exiting. [$(date)]"
505 eerror "Error: $MIRROR_DIRECTORY/debian does not seem to exist. Exiting." ; eend 1
508 echo "$MIRROR_SOURCES" >> "$SOURCES_LIST_OUTPUT"
511 if [ -n "$FAI_DEBOOTSTRAP" ] ; then
512 sed "s#^FAI_DEBOOTSTRAP=.*#FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"#" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
515 # does this suck? YES!
516 # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
518 unstable) SUITE='sid' ;;
519 # make sure that we *NEVER* write any broken suite name to sources.list,
520 # otherwise we won't be able to adjust it one next (correct) execution
528 *) echo "Sorry, $SUITE is not a valid Debian suite, exiting.">&2; bailout 1 ;;
530 export SUITE # make sure it's available in FAI scripts
532 if [ -n "${GRML_LIVE_SOURCES:-}" ] ; then
533 DIST=" etch\| stable\| lenny\| squeeze\| wheezy\| testing\| sid\| unstable"
534 echo "# generated based on \$GRML_LIVE_SOURCES by grml-live
535 $GRML_LIVE_SOURCES" | \
536 sed -e "s/\(^deb .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/;
537 s/\(^deb-src .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/" >> "$SOURCES_LIST_OUTPUT"
539 cat >> "$SOURCES_LIST_OUTPUT" << EOF
540 # generated by grml-live
541 deb http://deb.grml.org/ grml-stable main
542 deb http://deb.grml.org/ grml-testing main
543 deb http://cdn.debian.net/debian $SUITE main contrib non-free
547 # notice: activate grml-live pool when building against unstable or testing:
548 if grep -qwe unstable -qwe sid -qwe testing -qwe wheezy "$SOURCES_LIST_OUTPUT" ; then
549 grep -q 'grml-live.*main' "$SOURCES_LIST_OUTPUT" || \
550 grep grml-stable "$SOURCES_LIST_OUTPUT" | \
551 sed 's/grml-stable/grml-live/' >> "$SOURCES_LIST_OUTPUT"
553 grep -q 'grml-live.*main' "$SOURCES_LIST_OUTPUT" && \
554 sed -i 's/.*grml-live.*main/# removed grml-live repository/' "$SOURCES_LIST_OUTPUT"
557 for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" "$NFSROOT_CONF" ; do
558 if [ -n "$file" ] ; then
559 sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
563 # validate whether the specified architecture class matches the
564 # architecture (option), otherwise installation of kernel will fail
565 if echo $CLASSES | grep -qi i386 ; then
566 if ! [[ "$ARCH" == "i386" ]] ; then
567 log "Error: You specified the I386 class but are trying to build something else (AMD64?)."
568 eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
569 eerror "Tip: Either invoke grml-live with '-a i386' or adjust the architecture class. Exiting."
573 elif echo $CLASSES | grep -qi amd64 ; then
574 if ! [[ "$ARCH" == "amd64" ]] ; then
575 log "Error: You specified the AMD64 class but are trying to build something else (I386?)."
576 eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
577 eerror "Tip: Either invoke grml-live with '-a amd64' or adjust the architecture class. Exiting."
583 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
584 sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
586 sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
590 # CHROOT_OUTPUT - execute FAI {{{
591 if [ -n "$BUILD_DIRTY" ]; then
592 log "Skipping stage 'fai' as requested via option -B"
593 ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
595 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
597 # provide inform fai about the ISO we build
598 [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
599 echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
600 [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
601 [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
603 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
604 FAI_ACTION=softupdate
606 FAI_ACTION=dirinstall
609 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
610 if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
611 log "Error: does not look like you have a working chroot. Updating/building not possible."
612 eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
618 if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
619 log "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
620 ewarn "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
622 mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
624 if [ -n "${MIRROR_DIRECTORY}" ] ; then
625 mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
626 mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
629 # tell dpkg to use "unsafe io" during the build
630 [ -d "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d" ] || mkdir -p "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d"
631 echo force-unsafe-io > "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
633 log "Executed FAI command line:"
634 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"
635 BUILD_ONLY="$BUILD_ONLY" BOOTSTRAP_ONLY="$BOOTSTRAP_ONLY" fai $VERBOSE \
636 -C "$GRML_FAI_CONFIG" -s "file:///$GRML_FAI_CONFIG/config" -c"$CLASSES" \
637 -u "$HOSTNAME" "$FAI_ACTION" "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
638 RC="$PIPESTATUS" # notice: bash-only
640 rm -f "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
642 FORCE_ISO_REBUILD=true
644 if [ "$RC" != 0 ] ; then
645 log "Error: critical error while executing fai [exit code ${RC}]. Exiting."
646 eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
649 einfo "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
650 log "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
651 echo "$GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]" > $CHROOT_OUTPUT/etc/grml_version
652 chmod 644 $CHROOT_OUTPUT/etc/grml_version
653 einfo "Rebuilding initramfs"
654 # make sure new /etc/grml_version reaches initramfs, iterate over all
655 # present kernel versions (note: we can't really handle more than one
656 # kernel version anyway right now)
657 # chroot $CHROOT_OUTPUT update-initramfs -u -t => might break when using kernel-package :(
658 for initrd in "$(basename $CHROOT_OUTPUT/boot/vmlinuz-*)" ; do
659 if ! chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -c ; then
660 einfo "Creating fresh initrd did not work, trying update instead:"
661 log "Creating fresh initrd did not work, trying update instead:"
662 chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -u
668 # move fai logs into grml_logs directory
669 mkdir -p "$LOG_OUTPUT"/fai/
670 cp -r "$CHROOT_OUTPUT"/var/log/fai/"$HOSTNAME"/last/* "$LOG_OUTPUT"/fai/
671 chown root:adm "$LOG_OUTPUT"/fai/*
672 chmod 664 "$LOG_OUTPUT"/fai/*
673 rm -rf "$CHROOT_OUTPUT"/var/log/fai
675 # Remove all FAI logs from chroot if class RELEASE is used:
676 rm -f "$CHROOT_OUTPUT"/var/log/install_packages.list
680 # notice: 'fai dirinstall' does not seem to exit appropriate, so:
682 CHECKLOG=/var/log/fai/$HOSTNAME/last
683 if [ -r "$CHECKLOG/software.log" ] ; then
684 # 1 errors during executing of commands
685 grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
686 grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
687 grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
688 grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
689 grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
692 if [ -r "$CHECKLOG/shell.log" ] ; then
693 grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=6
696 if [ -n "$ERROR" ] ; then
697 log "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
698 eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
699 eerror "Note: check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
703 log "Finished execution of stage 'fai dirinstall' [$(date)]"
704 einfo "Finished execution of stage 'fai dirinstall'"
707 einfo "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
708 log "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
714 # package validator {{{
715 CHECKLOG=/var/log/fai/$HOSTNAME/last
717 if [ -r "$CHECKLOG/package_errors.log" ] && grep -q '[a-z]' "$CHECKLOG/package_errors.log" ; then
719 if [ -n "$EXIT_ON_MISSING_PACKAGES" -a -z "$BUILD_DIRTY" ] ; then
720 eerror "The following packages were requested for installation but could not be processed:"
721 cat $CHECKLOG/package_errors.log
722 eerror "... exiting as requested via \$EXIT_ON_MISSING_PACKAGES."
726 ewarn "The following packages were requested for installation but could not be processed:"
727 cat $CHECKLOG/package_errors.log
733 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
734 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
735 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
738 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
739 if [ -n "$BOOTSTRAP_ONLY" ] ; then
740 log "Skipping stage 'boot' as building with bootstrap only."
741 ewarn "Skipping stage 'boot' as building with bootstrap only." ; eend 0
743 if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
744 log "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already."
745 ewarn "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already." ; eend 0
748 [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
749 [ -d "$BUILD_OUTPUT"/boot/"${SHORT_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
751 # if we don't have an initrd we a) can't boot and b) there was an error
752 # during build, so check for the file:
753 INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
754 if [ -n "$INITRD" ] ; then
755 cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.gz
756 find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
758 log "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
759 eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
763 KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
764 if [ -n "$KERNEL_IMAGE" ] ; then
765 cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/linux26
767 log "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
768 eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
772 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
773 if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
774 log "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
775 eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
779 # copy _required_ isolinux files
780 for file in ifcpu64.c32 isolinux.bin vesamenu.c32; do
781 copy_addon_file "${file}" /usr/lib/syslinux isolinux
784 # *always* copy files to output directory so the variables
785 # get adjusted according to the build.
786 cp ${TEMPLATE_DIRECTORY}/boot/isolinux/* "$BUILD_OUTPUT"/boot/isolinux/
788 if [ -n "$NO_ADDONS" ] ; then
789 log "Skipping installation of boot addons as requested via \$NO_ADDONS."
790 einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
792 if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
793 log "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
794 ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
796 # copy addons from system packages or grml-live-compat
797 copy_addon_file ipxe.lkrn /usr/lib/ipxe addons
798 copy_addon_file pci.ids /usr/share/misc addons
799 copy_addon_file memtest86+.bin /boot addons
800 for file in memdisk chain.c32 hdt.c32 menu.c32; do
801 copy_addon_file "${file}" /usr/lib/syslinux addons
804 # make memtest filename FAT16/8.3 compatible
805 mv "${BUILD_OUTPUT}/boot/addons/memtest86+.bin" \
806 "${BUILD_OUTPUT}/boot/addons/memtest"
808 # copy only files so we can handle bsd4grml on its own
809 for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
810 test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
813 if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
814 log "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
815 einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
817 if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
818 cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
820 log "Missing addon file: bsd4grml"
821 ewarn "Missing addon file: bsd4grml" ; eend 0
825 fi # no "$TEMPLATE_DIRECTORY"/boot/addons
828 if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
829 mkdir -p "${BUILD_OUTPUT}/boot/grub"
831 cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
833 if [ -e ${TEMPLATE_DIRECTORY}/compat/grub/linux.mod ]; then
834 cp "${TEMPLATE_DIRECTORY}"/compat/grub/* "${BUILD_OUTPUT}"/boot/grub/
836 if ! which "grub-mkimage" >/dev/null 2>&1 ; then
837 log "grub-mkimage not found, skipping Grub step therefore." ; eend 0
838 ewarn "grub-mkimage not found, skipping Grub step therefore."
839 ewarn "Please install grub-pc-bin or grub-common >= 1.98+20100804-14." ; eend 0
840 elif ! grub-mkimage --help | grep -q -- --format ; then
841 log "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore." ; eend 0
842 ewarn "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore."
843 ewarn "Please install grub-common >= 1.98+20100804-14 or grub-pc-bin." ; eend 0
845 # copy system grub files if grml-live-compat is not installed
846 cp -a /usr/lib/grub/*-pc/*.mod "${BUILD_OUTPUT}"/boot/grub/
847 cp -a /usr/lib/grub/*-pc/*.o "${BUILD_OUTPUT}"/boot/grub/
848 cp -a /usr/lib/grub/*-pc/*.lst "${BUILD_OUTPUT}"/boot/grub/
849 cp -a /usr/share/grub/ascii.pf2 "${BUILD_OUTPUT}"/boot/grub/
850 grub-mkimage -d /usr/lib/grub/*-pc -o \
851 "${BUILD_OUTPUT}/boot/grub/core.img" biosdisk iso9660 --format=i386-pc
855 if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
856 log "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
857 eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
861 [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
862 cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
864 # adjust boot splash information:
865 RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
866 RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
867 RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
869 if [ -r "$BUILD_OUTPUT"/GRML/grml-version ] ; then
870 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
871 sed -i "s/%DATE%/$DATE/" "$BUILD_OUTPUT"/GRML/grml-version
874 # make sure the squashfs filename is set accordingly:
875 SQUASHFS_NAME="$GRML_NAME.squashfs"
877 if [ -n "$NO_BOOTID" ] ; then
878 log 'Skipping bootid feature as requested via $NO_BOOTID.'
879 einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
881 [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
882 [ -d "$BUILD_OUTPUT"/conf ] || mkdir "$BUILD_OUTPUT"/conf
883 einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
884 log "Generating /conf/bootid.txt with entry ${BOOTID}."
885 echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
889 # adjust all variables in the templates with the according distribution information
890 for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
891 "${BUILD_OUTPUT}"/boot/grub/* ; do
892 if [ -r "${file}" ] ; then
893 sed -i "s/%ARCH%/$ARCH/g" "${file}"
894 sed -i "s/%DATE%/$DATE/g" "${file}"
895 sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g" "${file}"
896 sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g" "${file}"
897 sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g" "${file}"
898 sed -i "s/%GRML_NAME%/$GRML_NAME/g" "${file}"
899 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g" "${file}"
900 sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g" "${file}"
901 sed -i "s/%SHORT_NAME%/$SHORT_NAME/g" "${file}"
902 sed -i "s/%VERSION%/$VERSION/g" "${file}"
904 [ -n "$DEFAULT_BOOTOPTIONS" ] && sed -i "s/ boot=live/ boot=live $DEFAULT_BOOTOPTIONS/" "${file}"
906 if [ -n "$NO_BOOTID" ] ; then
907 sed -i "s/ bootid=%BOOTID%//g" "${file}" # drop bootid bootoption
909 sed -i "s/%BOOTID%/$BOOTID/g" "${file}" # adjust bootid=... argument
914 # adjust bootsplash accordingly but make sure the string has the according lenght
915 SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
916 SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
917 for file in f4 f5 ; do
918 if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
919 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
920 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
924 # generate addon list
925 rm -f "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
926 for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
927 include_name=$(basename "$name")
928 echo "include $include_name" >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
931 if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
932 log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
933 echo "include grmlmain.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
934 echo "include default.cfg" > "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
935 echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
936 echo "include grml.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
938 for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
939 echo "include $(basename $f)" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
942 echo "include options.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
943 if [ ! -n "$NO_ADDONS" ] ; then
944 echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
946 echo "include isoprompt.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
947 echo "include hd.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
948 echo "include hidden.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
949 else # assume we are building a custom distribution:
950 log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
951 einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
952 if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
953 log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
955 einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
959 log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
960 echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
961 [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
965 # use old style console based isolinux method only if requested:
966 if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
967 log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
968 einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
969 if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
970 einfo "include for console.cfg already found, nothing to do."
973 log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
974 einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
975 echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
979 log 'Using graphical boot menu.'
980 if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
981 log "include for vesamenu.cfg already found, nothing to do."
983 log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
984 echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
988 if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
989 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
992 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
993 if ! [ -r "$DPKG_LIST" ] ; then
994 ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
996 einfo "Storing package list information as /GRML/${GRML_NAME}-packages.txt on ISO."
997 cp "$DPKG_LIST" "${BUILD_OUTPUT}/GRML/${GRML_NAME}-packages.txt"
1001 # autostart for Windows:
1002 if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
1003 cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
1006 FORCE_ISO_REBUILD=true
1007 einfo "Finished execution of stage 'boot'" ; eend 0
1011 log 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
1012 eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
1016 # support installation of local files into the chroot/ISO
1017 if [ -n "$CHROOT_INSTALL" ] ; then
1018 if ! [ -d "$CHROOT_INSTALL" ] ; then
1019 log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1020 ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1022 log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1023 einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1024 rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
1026 einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
1027 FORCE_ISO_REBUILD=true
1031 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
1032 log "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
1033 ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
1034 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
1035 log "Skipping stage 'squashfs' as requested via option -q or -N"
1036 ewarn "Skipping stage 'squashfs' as requested via option -q or -N" ; eend 0
1038 [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
1039 # make sure we don't leave (even an empty) base.tgz:
1040 [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
1042 # if unconfigured default to squashfs-tools' mksquashfs binary
1043 if [ -z "$SQUASHFS_BINARY" ] ; then
1044 SQUASHFS_BINARY='mksquashfs'
1047 if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
1048 log "Using mksquashfs binary ${SQUASHFS_BINARY}"
1049 einfo "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
1051 log "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
1052 eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
1056 # use sane defaults if $SQUASHFS_OPTIONS isn't set
1057 if [ -z "$SQUASHFS_OPTIONS" ] ; then
1058 # use blocksize 256k as this gives best result with regards to time + compression
1059 SQUASHFS_OPTIONS="-b 256k"
1061 # set lzma/xz compression by default, unless -z option has been specified on command line
1062 if [ -z "$SQUASHFS_ZLIB" ] ; then
1063 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp xz"
1065 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp gzip"
1069 # support exclusion of files via exclude-file:
1070 if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
1071 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE -wildcards"
1074 # get rid of unnecessary files when building grml-small for final release:
1075 if echo "$CLASSES" | grep -q GRML_SMALL ; then
1076 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
1080 SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
1082 # informational stuff
1083 [ -n "$SQUASHFS_OPTIONS" ] && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
1084 [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
1085 einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
1087 log "$SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS"
1089 if $SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
1090 -noappend $SQUASHFS_OPTIONS 2>"${SQUASHFS_STDERR}" ; then
1091 echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
1092 log "Finished execution of stage 'squashfs' [$(date)]"
1093 einfo "Finished execution of stage 'squashfs'" ; eend 0
1095 log "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1096 log "$(cat $SQUASHFS_STDERR)"
1097 eerror "Error: there was a critical error executing stage 'squashfs':"
1098 cat "${SQUASHFS_STDERR}"
1103 FORCE_ISO_REBUILD=true
1106 # create md5sum file:
1107 if [ -z "$BOOTSTRAP_ONLY" ] ; then
1108 ( cd $BUILD_OUTPUT/GRML &&
1109 find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1113 # ISO_OUTPUT - mkisofs {{{
1114 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1115 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1117 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1118 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1119 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1120 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1123 # Just until http://bts.grml.org/grml/issue945 has been resolved.
1124 # HYBRID_METHOD defaults to manifold, so make sure the default works OOTB.
1125 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1126 log "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1127 ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1128 HYBRID_METHOD='grub2'
1132 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ] ; then
1133 log "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1134 ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1135 elif [ -n "$SKIP_MKISOFS" ] ; then
1136 log "Skipping stage 'iso build' as requested via option -n or -N"
1137 ewarn "Skipping stage 'iso build' as requested via option -n or -N" ; eend 0
1139 mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1141 if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1142 log "Forcing rebuild of ISO because files on ISO have been modified."
1143 einfo "Forcing rebuild of ISO because files on ISO have been modified."
1146 # support mkisofs as well as genisoimage
1147 if which mkisofs >/dev/null 2>&1; then
1149 elif which genisoimage >/dev/null 2>&1; then
1150 MKISOFS='genisoimage'
1152 log "Error: neither mkisofs nor genisoimage available - can not create ISO."
1153 eerror "Error: neither mkisofs nor genisoimage available - can not create ISO." ; eend 1
1158 if cd "$BUILD_OUTPUT" ; then
1159 if [ "$BOOT_METHOD" = "grub2" ]; then
1160 # make a 2048-byte bootsector for El Torito
1161 dd if=/dev/zero of=boot/grub/toriboot.bin bs=512 count=4 2>/dev/null
1162 # those are in 2048-byte sectors, so 1 16 matches 4 63 below
1163 echo 1 16 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -B 11 | \
1164 dd of=boot/grub/toriboot.bin conv=notrunc 2>/dev/null
1166 log "$MKISOFS -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J $BOOT_ARGS -o ${ISO_OUTPUT}/${ISO_NAME} ."
1167 "$MKISOFS" -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1168 -l -r -J $BOOT_ARGS -no-pad \
1169 -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1170 # both of these need core.img there, so it’s easier to write it here
1171 if [ "$BOOT_METHOD" = "grub2" ] || [ "$HYBRID_METHOD" = "grub2" ]; then
1172 # must be <= 30720 bytes
1173 dd if=boot/grub/core.img of="${ISO_OUTPUT}/${ISO_NAME}" \
1174 conv=notrunc bs=512 seek=4 2>/dev/null
1177 # pad the output ISO to multiples of 256 KiB for partition table support
1178 siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1179 cyls=$((siz / 512 / 32 / 16 + 1)) # C=$cyls H=16 S=32
1180 siz=$((cyls * 16 * 32 * 512)) # size after padding
1181 dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1182 of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1184 # support disabling hybrid ISO image
1185 if [ "$HYBRID_METHOD" = "disable" ] ; then\
1186 log "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1187 einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1189 # use isohybrid only on request
1190 elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
1191 if ! which isohybrid >/dev/null 2>&1 ; then
1192 bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1194 log "Creating hybrid ISO file with isohybrid method"
1195 einfo "Creating hybrid ISO file with isohybrid method"
1196 # Notes for consideration:
1197 # "-entry 4 -type 1c"
1198 # * using 4 as the partition number is supposed to help with BIOSes
1199 # that only support USB-Zip boot
1200 # * using 1c (i.e. hidden FAT32 LBA), instead of the default 0x17
1201 # (hidden NTFS, IIRC), as the partition type is sometimes needed
1202 # to get the BIOS even look at the partition created by isohybrid
1203 isohybrid "${ISO_OUTPUT}/${ISO_NAME}"
1206 # by default use our manifold boot method:
1208 # isoinfo is part of both mkisofs and genisoimage so we're good
1209 bootoff=$(isoinfo -l -i "${ISO_OUTPUT}/${ISO_NAME}" | \
1210 sed -n '/^.*\[ *\([0-9]*\)[] ].* ISOLINUX.BIN;1 *$/s//\1/p')
1211 if ! [ -r boot/grub/core.img ] ; then
1212 ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1213 elif [ "${bootoff:-0}" -lt 1 ] ; then
1214 ewarn "isolinux.bin not found on the ISO file, disabling manifold boot"
1216 log "Creating hybrid ISO file with manifold method"
1217 einfo "Creating hybrid ISO file with manifold method"
1218 if [ "$HYBRID_METHOD" = "grub2" ] ; then
1219 # 512 bytes: MBR, partition table, load GRUB 2
1220 echo 4 63 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 4:0x96 -g $cyls:16:32
1222 # read only one but 2048-byte sized (scale: << 2) sector
1223 echo $bootoff $bootoff | \
1224 mksh /usr/share/grml-live/scripts/bootilnx.mksh -A -M 4:0x96 -g $cyls:16:32 -S 2
1225 fi | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1230 # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1231 case $CLASSES in *RELEASE*)
1234 if cd $ISO_OUTPUT ; then
1235 md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1236 touch -r ${ISO_NAME} ${ISO_NAME}.md5
1237 sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1238 touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1247 if [ "$RC" = 0 ] ; then
1248 log "Finished execution of stage 'iso build' [$(date)]"
1249 einfo "Finished execution of stage 'iso build'" ; eend 0
1251 log "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1252 eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1258 # pack artifacts {{{
1259 if [ -n "$PACK_ARTIFACTS" ]; then
1260 log "Packing artifcats"
1261 einfo "Packing artifacts"
1262 [ -f "${CHROOT_ARCHIVE}" ] && rm -r "${CHROOT_ARCHIVE}"
1263 tar -c -a -f ${CHROOT_ARCHIVE} --preserve-permissions -C "$(dirname ${CHROOT_OUTPUT})" "$(basename ${CHROOT_OUTPUT})"
1268 # log build information to database if grml-live-db is installed and enabled {{{
1270 if [ -d /usr/share/grml-live-db ] ; then
1273 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1274 [ -n "$DPKG_DATABASE" ] || DPKG_DATABASE=/var/log/grml-live.db
1275 [ -n "$DPKG_DBSCRIPT" ] || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1276 [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1278 if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1279 log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1280 eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1284 # disable by default for now, not sure whether really everyone is using a local db file
1285 #if ! touch "$DPKG_DATABASE" ; then
1286 # eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1290 if ! [ -r "$DPKG_LIST" ] ; then
1291 log "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1292 ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1294 einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1295 log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1296 log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1299 if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1315 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1316 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1318 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1320 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1324 ## END OF FILE #################################################################
1325 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2