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 umount "${CHROOT_OUTPUT}/grml-live/sources/" 2>/dev/null || /bin/true
153 [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
159 rm -f /var/run/fai/fai_softupdate_is_running \
160 /var/run/fai/FAI_INSTALLATION_IN_PROGRESS
161 [ -n "$SQUASHFS_STDERR" ] && rm -rf "$SQUASHFS_STDERR"
163 [ -n "$1" ] && EXIT="$1" || EXIT="1"
164 [ -n "$2" ] && eerror "$2">&2
165 if [ -n "$PACK_ARTIFACTS" ]; then
168 [ -n "${BUILD_OUTPUT}" -a -d "${BUILD_OUTPUT}" ] && rm -r "${BUILD_OUTPUT}"
169 [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && rm -r "${CHROOT_OUTPUT}"
172 if [ -n "$CHOWN_USER" ]; then
173 log "Setting ownership"
174 einfo "Setting ownership"
175 [ -n "${OUTPUT}" -a -d "${OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${OUTPUT}"
176 [ -n "${BUILD_OUTPUT}" -a -d "${BUILD_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${BUILD_OUTPUT}"
177 [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${CHROOT_OUTPUT}"
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}"
180 [ -n "${CHROOT_ARCHIVE}" -a -f "${CHROOT_ARCHIVE}" ] && chown -R "${CHOWN_USER}:" "${CHROOT_ARCHIVE}"
183 log "------------------------------------------------------------------------------"
186 trap bailout 1 2 3 3 6 9 14 15
190 # some important functions {{{
193 # usage: log "string to log"
194 log() { echo "$*" >> $LOGFILE ; }
196 # cut string at character number int = $1
197 # usage: cut_string 5 "1234567890" will output "12345"
199 [ -n "$2" ] || return 1
200 echo "$2" | head -c "$1"; echo -ne "\n"
203 # prepend int = $1 spaces before string = $2
204 # usage: extend_string_begin 5 "123" will output " 123"
205 extend_string_begin() {
206 [ -n "$2" ] || return 1
207 local COUNT="$(echo $2 | wc -c)"
208 local FILL="$(expr $COUNT - $1)"
209 while [ "$FILL" -gt 1 ] ; do
211 local FILL=$(expr $FILL - 1)
213 while [ "$FILL" -lt 1 ] ; do
215 local FILL=$(expr $FILL + 1)
217 echo "$2" | head -c "$1"; echo -ne "\n"
220 # append int = $1 spaces to string = $2
221 # usage: extend_string_begin 5 "123" will output "123 "
222 extend_string_end() {
223 [ -n "$2" ] || return 1
224 echo -n "$2" | head -c "$1"
225 local COUNT="$(echo $2 | wc -c)"
226 local FILL="$(expr $COUNT - $1)"
227 while [ "$FILL" -gt 1 ] ; do
229 local FILL=$(expr $FILL - 1)
231 while [ "$FILL" -lt 1 ] ; do
233 local FILL=$(expr $FILL + 1)
238 # Copy addonfile $1 from either
239 # * the chroot (via $2, the system path),
240 # * or from TEMPLATE_DIRECTORY/compat (if exists),
241 # * or from the host system (again, using $2),
242 # or warn about the missing file.
245 # * We assume that the chroot always has a "good" version of
246 # the file. Also it makes sources handling easier.
247 # * On unstable, we Recommend the Debian packages containing
248 # these files. The user can override them by putting his
249 # "better" version into the chroot.
250 # * On stable, the Debian packages are probably not available,
251 # or outdated, so we look in TEMPLATE_DIRECTORY/compat first, where
252 # our grml-live-compat package installs current file versions.
254 DEST="${BUILD_OUTPUT}/boot/$3"
255 if [ ! -d "${DEST}/" ]; then
258 if [ -e "$CHROOT_OUTPUT/$2/$1" ]; then
259 log "Copying $1 from chroot"
260 cp "$CHROOT_OUTPUT/$2/$1" "${DEST}/"
263 if [ -e "${TEMPLATE_DIRECTORY}/compat/$3/$1" ]; then
264 log "Copying $1 from grml-live-compat"
265 cp "${TEMPLATE_DIRECTORY}/compat/$3/$1" "${DEST}/"
268 if [ -e "$2/$1" ]; then
269 log "Copying $1 from system"
270 cp "$2/$1" "${DEST}/"
274 msg="Missing addon file: \"$1\""
275 ewarn "$msg" ; eend 1
276 log "copy_addon_file: $msg"
280 # read local (non-packaged) configuration {{{
281 LOCAL_CONFIG=/etc/grml/grml-live.local
282 if [ -r "$LOCAL_CONFIG" ] ; then
288 if [ -n "${GRML_LIVE_SOURCES:-}" ] ; then
289 eerror "Config variable \$GRML_LIVE_SOURCES is set. This variable has been deprecated."
290 ewarn "Please set up ${GRML_FAI_CONFIG}/config/files/etc/apt/sources.list.d/* instead."
295 # command line parsing {{{
296 while getopts "a:C:c:d:D:g:i:I:o:r:s:t:U:v:AbBFnNquVz" opt; do
299 A) PACK_ARTIFACTS=1 ;;
302 c) CLASSES="$OPTARG" ;;
303 C) CONFIG="$OPTARG" ;;
305 D) GRML_FAI_CONFIG="$OPTARG" ;;
306 g) GRML_NAME="$OPTARG" ;;
307 i) ISO_NAME="$OPTARG" ;;
308 I) CHROOT_INSTALL="$OPTARG" ;;
310 N) BOOTSTRAP_ONLY=1; SKIP_MKISOFS=1; SKIP_MKSQUASHFS=1 ;;
311 o) OUTPUT="$OPTARG" ;;
312 q) SKIP_MKSQUASHFS=1 ;;
313 r) RELEASENAME="$OPTARG" ;;
314 s) SUITE="$OPTARG" ;;
315 t) TEMPLATE_DIRECTORY="$OPTARG";;
316 v) VERSION="$OPTARG" ;;
319 U) CHOWN_USER="$OPTARG" ;;
321 z) SQUASHFS_ZLIB=1 ;;
322 ?) echo "invalid option -$OPTARG" >&2; bailout 1 ;;
325 shift $(($OPTIND - 1)) # set ARGV to the first not parsed commandline parameter
328 # assume sane defaults (if not set already) {{{
329 [ -n "$ARCH" ] || ARCH="$(dpkg --print-architecture)"
330 [ -n "$BOOT_METHOD" ] || BOOT_METHOD='isolinux'
331 [ -n "$CLASSES" ] || CLASSES="GRMLBASE,GRML_MEDIUM,I386"
332 [ -n "$DATE" ] || DATE="$(date +%Y-%m-%d)"
333 [ -n "$DISTRI_INFO" ] || DISTRI_INFO='Grml - Live Linux for system administrators '
334 [ -n "$DISTRI_NAME" ] || DISTRI_NAME="grml"
335 [ -n "$DISTRI_SPLASH" ] || DISTRI_SPLASH='grml.png'
336 [ -n "$FORCE_ISO_REBUILD" ] || FORCE_ISO_REBUILD="false"
337 [ -n "$GRML_FAI_CONFIG" ] || GRML_FAI_CONFIG='/etc/grml/fai'
338 [ -n "$GRML_NAME" ] || GRML_NAME='grml'
339 [ -n "$HOSTNAME" ] || HOSTNAME='grml'
340 [ -n "$HYBRID_METHOD" ] || HYBRID_METHOD='manifold'
341 [ -n "$NFSROOT_CONF" ] || NFSROOT_CONF="${GRML_FAI_CONFIG}/make-fai-nfsroot.conf"
342 [ -n "$RELEASENAME" ] || RELEASENAME='grml-live rocks'
343 [ -n "$SQUASHFS_EXCLUDES_FILE" ] || SQUASHFS_EXCLUDES_FILE="${GRML_FAI_CONFIG}/config/grml/squashfs-excludes"
344 [ -n "$SUITE" ] || SUITE='squeeze'
345 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
346 [ -n "$USERNAME" ] || USERNAME='grml'
347 [ -n "$VERSION" ] || VERSION='0.0.1'
349 # output specific stuff, depends on $OUTPUT (iff not set):
350 [ -n "$OUTPUT" ] || OUTPUT='/grml/grml-live'
351 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
352 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
353 [ -n "$CHROOT_ARCHIVE" ] || CHROOT_ARCHIVE="$OUTPUT/$(basename $CHROOT_OUTPUT).tgz"
354 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
355 [ -n "$LOG_OUTPUT" ] || LOG_OUTPUT="$OUTPUT/grml_logs"
358 # some misc checks before executing FAI {{{
359 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
360 specify it on the command line using the -c option."
361 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
362 specify it on the command line using the -o option."
364 # trim characters that are known to cause problems inside $GRML_NAME;
365 # for example isolinux does not like '-' inside the directory name
366 [ -n "$GRML_NAME" ] && export SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
368 # export variables to have them available in fai scripts:
369 [ -n "$GRML_NAME" ] && export GRML_NAME="$GRML_NAME"
370 [ -n "$RELEASENAME" ] && export RELEASENAME="$RELEASENAME"
373 # ZERO_LOGFILE - check for backwards compatibility reasons {{{
374 # this was default behaviour until grml-live 0.9.34:
375 if [ -n "$ZERO_LOGFILE" ] ; then
376 PRESERVE_LOGFILE='' # make sure it's cleaned then
377 ewarn "Please consider disabling the \$ZERO_LOGFILE option as grml-live clears..."
378 ewarn "... the logfile $LOGFILE by default (unless \$PRESERVE_LOGFILE is set) nowadays."
383 # ask user whether the setup is ok {{{
384 if [ -z "$FORCE" ] ; then
386 echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
388 echo " FAI classes: $CLASSES"
389 [ -r "$LOCAL_CONFIG" ] && echo " Local config: /etc/grml/grml-live.local"
390 [ -n "$CONFIG" ] && echo " Configuration: $CONFIG"
391 [ -n "$GRML_FAI_CONFIG" ] && echo " Config directory: $GRML_FAI_CONFIG"
392 echo " main directory: $OUTPUT"
393 [ -n "$CHROOT_OUTPUT" ] && echo " Chroot target: $CHROOT_OUTPUT"
394 [ -n "$BUILD_OUTPUT" ] && echo " Build target: $BUILD_OUTPUT"
395 [ -n "$ISO_OUTPUT" ] && echo " ISO target: $ISO_OUTPUT"
396 [ -n "$GRML_NAME" ] && echo " Grml name: $GRML_NAME"
397 [ -n "$RELEASENAME" ] && echo " Release name: $RELEASENAME"
398 [ -n "$DATE" ] && echo " Build date: $DATE"
399 [ -n "$VERSION" ] && echo " Grml version: $VERSION"
400 [ -n "$SUITE" ] && echo " Debian suite: $SUITE"
401 [ -n "$ARCH" ] && echo " Architecture: $ARCH"
402 [ -n "$BOOT_METHOD" ] && echo " Boot method: $BOOT_METHOD"
403 [ -n "$HYBRID_METHOD" ] && echo " Hybrid method: $HYBRID_METHOD"
404 [ -n "$TEMPLATE_DIRECTORY" ] && echo " Template files: $TEMPLATE_DIRECTORY"
405 [ -n "$CHROOT_INSTALL" ] && echo " Install files from directory to chroot: $CHROOT_INSTALL"
406 [ -n "$BOOTID" ] && echo " Boot identifier: $BOOTID"
407 [ -n "$NO_BOOTID" ] && echo " Skipping bootid feature."
408 [ -n "$CHOWN_USER" ] && echo " Output owner: $CHOWN_USER"
409 [ -n "$DEFAULT_BOOTOPTIONS" ] && echo " Adding default bootoptions: \"$DEFAULT_BOOTOPTIONS\""
410 [ -n "$FAI_ARGS" ] && echo " Additional arguments for FAI: $FAI_ARGS"
411 [ -n "$LOGFILE" ] && echo " Logging to file: $LOGFILE"
412 [ -n "$SQUASHFS_ZLIB" ] && echo " Using ZLIB (instead of LZMA/XZ) compression."
413 [ -n "$SQUASHFS_OPTIONS" ] && echo " Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
414 [ -n "$VERBOSE" ] && echo " Using VERBOSE mode."
415 [ -n "$PACK_ARTIFACTS" ] && echo " Will prepare packed artifacts and ensure clean build."
416 [ -n "$UPDATE" ] && echo " Executing UPDATE instead of fresh installation."
417 if [ -n "$BOOTSTRAP_ONLY" ] ; then
418 echo " Bootstrapping only and not building (files for) ISO."
420 [ -n "$SKIP_MKSQUASHFS" ] && echo " Skipping creation of SQUASHFS file."
421 [ -n "$SKIP_MKISOFS" ] && echo " Skipping creation of ISO file."
422 [ -n "$BUILD_ONLY" ] && echo " Executing BUILD_ONLY instead of fresh installation or UPDATE."
423 [ -n "$BUILD_DIRTY" ] && echo " Executing BUILD_DIRTY to leave chroot untouched."
426 echo -n "Is this ok for you? [y/N] "
428 if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
429 bailout 1 "Exiting as requested."
435 # clean up before start {{{
436 if [ -n "${PACK_ARTIFACTS}" ]; then
437 echo "Wiping old artifacts"
438 [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && rm -r "${CHROOT_OUTPUT}"
439 [ -n "${BUILD_OUTPUT}" -a -d "${BUILD_OUTPUT}" ] && rm -r "${BUILD_OUTPUT}"
440 [ -n "${ISO_OUTPUT}" -a -d "${ISO_OUTPUT}" ] && rm -r "${ISO_OUTPUT}"
441 [ -n "${LOG_OUTPUT}" -a -d "${LOG_OUTPUT}" ] && rm -r "${LOG_OUTPUT}"
442 [ -n "${CHROOT_ARCHIVE}" -a -f "${CHROOT_ARCHIVE}" ] && rm "${CHROOT_ARCHIVE}"
446 # create log file {{{
447 [ -n "$LOGFILE" ] || LOGFILE=${LOG_OUTPUT}/grml-live.log
448 mkdir -p $(dirname "${LOGFILE}")
450 chown root:adm $LOGFILE
454 # clean/zero/remove logfiles {{{
456 if [ -n "$PRESERVE_LOGFILE" ] ; then
457 echo "Preserving logfile $LOGFILE as requested via \$PRESERVE_LOGFILE"
459 # make sure it is empty (as it is e.g. appended to grml-live-db)
463 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
464 if [ -d /var/log/fai/"$HOSTNAME" ] ; then
465 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
466 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
467 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
468 rm -f /var/log/fai/"$HOSTNAME"/last \
469 /var/log/fai/"$HOSTNAME"/last-dirinstall \
470 /var/log/fai/"$HOSTNAME"/last-softupdate
475 # source config and startup {{{
476 if [ -n "$CONFIG" ] ; then
477 if ! [ -f "$CONFIG" ] ; then
478 log "Error: $CONFIG could not be read. Exiting. [$(date)]"
479 eerror "Error: $CONFIG could not be read. Exiting." ; eend 1
482 log "Sourcing $CONFIG"
487 start_seconds=$(cut -d . -f 1 /proc/uptime)
488 log "------------------------------------------------------------------------------"
489 log "Starting grml-live [${GRML_LIVE_VERSION}] run on $(date)"
490 if [ -n "$LOCAL_CONFIG" ]; then
491 log "Using local config file: $LOCAL_CONFIG"
493 log "Executed grml-live command line:"
496 einfo "Logging actions to logfile $LOGFILE"
499 # on-the-fly configuration {{{
500 if [ -n "$FAI_DEBOOTSTRAP" ] ; then
501 sed "s#^FAI_DEBOOTSTRAP=.*#FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"#" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
504 # does this suck? YES!
505 # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
507 unstable) SUITE='sid' ; CLASSES="DEBIAN_UNSTABLE,$CLASSES" ;;
508 *) CLASSES="DEBIAN_$(echo $SUITE | tr 'a-z' 'A-Z'),$CLASSES";;
510 export SUITE # make sure it's available in FAI scripts
512 for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" "$NFSROOT_CONF" ; do
513 if [ -n "$file" ] ; then
514 sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
518 # validate whether the specified architecture class matches the
519 # architecture (option), otherwise installation of kernel will fail
520 if echo $CLASSES | grep -qi i386 ; then
521 if ! [[ "$ARCH" == "i386" ]] ; then
522 log "Error: You specified the I386 class but are trying to build something else (AMD64?)."
523 eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
524 eerror "Tip: Either invoke grml-live with '-a i386' or adjust the architecture class. Exiting."
528 elif echo $CLASSES | grep -qi amd64 ; then
529 if ! [[ "$ARCH" == "amd64" ]] ; then
530 log "Error: You specified the AMD64 class but are trying to build something else (I386?)."
531 eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
532 eerror "Tip: Either invoke grml-live with '-a amd64' or adjust the architecture class. Exiting."
538 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
539 sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
541 sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
545 # CHROOT_OUTPUT - execute FAI {{{
546 if [ -n "$BUILD_DIRTY" ]; then
547 log "Skipping stage 'fai' as requested via option -B"
548 ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
550 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
552 # provide inform fai about the ISO we build
553 [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
554 echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
555 [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
556 [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
558 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
559 FAI_ACTION=softupdate
561 FAI_ACTION=dirinstall
564 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
565 if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
566 log "Error: does not look like you have a working chroot. Updating/building not possible."
567 eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
573 if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
574 log "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
575 ewarn "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
577 mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
579 if [ -n "${MIRROR_DIRECTORY}" ] ; then
580 mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
581 mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
584 mkdir -p "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
585 mount --bind "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
587 # tell dpkg to use "unsafe io" during the build
588 [ -d "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d" ] || mkdir -p "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d"
589 echo force-unsafe-io > "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
591 log "Executed FAI command line:"
592 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"
593 BUILD_ONLY="$BUILD_ONLY" BOOTSTRAP_ONLY="$BOOTSTRAP_ONLY" fai $VERBOSE \
594 -C "$GRML_FAI_CONFIG" -s "file:///$GRML_FAI_CONFIG/config" -c"$CLASSES" \
595 -u "$HOSTNAME" "$FAI_ACTION" "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
596 RC="$PIPESTATUS" # notice: bash-only
598 rm -f "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
600 FORCE_ISO_REBUILD=true
602 if [ "$RC" != 0 ] ; then
603 log "Error: critical error while executing fai [exit code ${RC}]. Exiting."
604 eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
607 einfo "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
608 log "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
609 echo "$GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]" > $CHROOT_OUTPUT/etc/grml_version
610 chmod 644 $CHROOT_OUTPUT/etc/grml_version
611 einfo "Rebuilding initramfs"
612 # make sure new /etc/grml_version reaches initramfs, iterate over all
613 # present kernel versions (note: we can't really handle more than one
614 # kernel version anyway right now)
615 # chroot $CHROOT_OUTPUT update-initramfs -u -t => might break when using kernel-package :(
616 for initrd in "$(basename $CHROOT_OUTPUT/boot/vmlinuz-*)" ; do
617 if ! chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -c ; then
618 einfo "Creating fresh initrd did not work, trying update instead:"
619 log "Creating fresh initrd did not work, trying update instead:"
620 chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -u
626 # move fai logs into grml_logs directory
627 mkdir -p "$LOG_OUTPUT"/fai/
628 cp -r "$CHROOT_OUTPUT"/var/log/fai/"$HOSTNAME"/last/* "$LOG_OUTPUT"/fai/
629 chown root:adm "$LOG_OUTPUT"/fai/*
630 chmod 664 "$LOG_OUTPUT"/fai/*
631 rm -rf "$CHROOT_OUTPUT"/var/log/fai
633 # Remove all FAI logs from chroot if class RELEASE is used:
634 rm -f "$CHROOT_OUTPUT"/var/log/install_packages.list
638 # notice: 'fai dirinstall' does not seem to exit appropriate, so:
640 CHECKLOG=/var/log/fai/$HOSTNAME/last
641 if [ -r "$CHECKLOG/software.log" ] ; then
642 # 1 errors during executing of commands
643 grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
644 grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
645 grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
646 grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
647 grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
650 if [ -r "$CHECKLOG/shell.log" ] ; then
651 grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=6
654 if [ -n "$ERROR" ] ; then
655 log "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
656 eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
657 eerror "Note: check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
661 log "Finished execution of stage 'fai dirinstall' [$(date)]"
662 einfo "Finished execution of stage 'fai dirinstall'"
665 einfo "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
666 log "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
672 # package validator {{{
673 CHECKLOG=/var/log/fai/$HOSTNAME/last
675 if [ -r "$CHECKLOG/package_errors.log" ] && grep -q '[a-z]' "$CHECKLOG/package_errors.log" ; then
677 if [ -n "$EXIT_ON_MISSING_PACKAGES" -a -z "$BUILD_DIRTY" ] ; then
678 eerror "The following packages were requested for installation but could not be processed:"
679 cat $CHECKLOG/package_errors.log
680 eerror "... exiting as requested via \$EXIT_ON_MISSING_PACKAGES."
684 ewarn "The following packages were requested for installation but could not be processed:"
685 cat $CHECKLOG/package_errors.log
691 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
692 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
693 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
696 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
697 if [ -n "$BOOTSTRAP_ONLY" ] ; then
698 log "Skipping stage 'boot' as building with bootstrap only."
699 ewarn "Skipping stage 'boot' as building with bootstrap only." ; eend 0
701 if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
702 log "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already."
703 ewarn "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already." ; eend 0
706 [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
707 [ -d "$BUILD_OUTPUT"/boot/"${SHORT_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
709 # if we don't have an initrd we a) can't boot and b) there was an error
710 # during build, so check for the file:
711 INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
712 if [ -n "$INITRD" ] ; then
713 cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.gz
714 find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
716 log "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
717 eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
721 KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
722 if [ -n "$KERNEL_IMAGE" ] ; then
723 cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/linux26
725 log "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
726 eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
730 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
731 if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
732 log "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
733 eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
737 # copy _required_ isolinux files
738 for file in ifcpu64.c32 isolinux.bin vesamenu.c32; do
739 copy_addon_file "${file}" /usr/lib/syslinux isolinux
742 # *always* copy files to output directory so the variables
743 # get adjusted according to the build.
744 cp ${TEMPLATE_DIRECTORY}/boot/isolinux/* "$BUILD_OUTPUT"/boot/isolinux/
746 if [ -n "$NO_ADDONS" ] ; then
747 log "Skipping installation of boot addons as requested via \$NO_ADDONS."
748 einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
750 if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
751 log "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
752 ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
754 # copy addons from system packages or grml-live-compat
755 copy_addon_file ipxe.lkrn /usr/lib/ipxe addons
756 copy_addon_file pci.ids /usr/share/misc addons
757 copy_addon_file memtest86+.bin /boot addons
758 for file in memdisk chain.c32 hdt.c32 menu.c32; do
759 copy_addon_file "${file}" /usr/lib/syslinux addons
762 # make memtest filename FAT16/8.3 compatible
763 mv "${BUILD_OUTPUT}/boot/addons/memtest86+.bin" \
764 "${BUILD_OUTPUT}/boot/addons/memtest"
766 # copy only files so we can handle bsd4grml on its own
767 for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
768 test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
771 if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
772 log "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
773 einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
775 if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
776 cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
778 log "Missing addon file: bsd4grml"
779 ewarn "Missing addon file: bsd4grml" ; eend 0
783 fi # no "$TEMPLATE_DIRECTORY"/boot/addons
786 if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
787 mkdir -p "${BUILD_OUTPUT}/boot/grub"
789 cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
791 if [ -e ${TEMPLATE_DIRECTORY}/compat/grub/linux.mod ]; then
792 cp "${TEMPLATE_DIRECTORY}"/compat/grub/* "${BUILD_OUTPUT}"/boot/grub/
794 if ! which "grub-mkimage" >/dev/null 2>&1 ; then
795 log "grub-mkimage not found, skipping Grub step therefore." ; eend 0
796 ewarn "grub-mkimage not found, skipping Grub step therefore."
797 ewarn "Please install grub-pc-bin or grub-common >= 1.98+20100804-14." ; eend 0
798 elif ! grub-mkimage --help | grep -q -- --format ; then
799 log "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore." ; eend 0
800 ewarn "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore."
801 ewarn "Please install grub-common >= 1.98+20100804-14 or grub-pc-bin." ; eend 0
803 # copy system grub files if grml-live-compat is not installed
804 cp -a /usr/lib/grub/*-pc/*.mod "${BUILD_OUTPUT}"/boot/grub/
805 cp -a /usr/lib/grub/*-pc/*.o "${BUILD_OUTPUT}"/boot/grub/
806 cp -a /usr/lib/grub/*-pc/*.lst "${BUILD_OUTPUT}"/boot/grub/
807 cp -a /usr/share/grub/ascii.pf2 "${BUILD_OUTPUT}"/boot/grub/
808 grub-mkimage -d /usr/lib/grub/*-pc -o \
809 "${BUILD_OUTPUT}/boot/grub/core.img" biosdisk iso9660 --format=i386-pc
813 if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
814 log "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
815 eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
819 [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
820 cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
822 # adjust boot splash information:
823 RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
824 RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
825 RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
827 if [ -r "$BUILD_OUTPUT"/GRML/grml-version ] ; then
828 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
829 sed -i "s/%DATE%/$DATE/" "$BUILD_OUTPUT"/GRML/grml-version
832 # make sure the squashfs filename is set accordingly:
833 SQUASHFS_NAME="$GRML_NAME.squashfs"
835 if [ -n "$NO_BOOTID" ] ; then
836 log 'Skipping bootid feature as requested via $NO_BOOTID.'
837 einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
839 [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
840 [ -d "$BUILD_OUTPUT"/conf ] || mkdir "$BUILD_OUTPUT"/conf
841 einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
842 log "Generating /conf/bootid.txt with entry ${BOOTID}."
843 echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
847 # adjust all variables in the templates with the according distribution information
848 for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
849 "${BUILD_OUTPUT}"/boot/grub/* ; do
850 if [ -r "${file}" ] ; then
851 sed -i "s/%ARCH%/$ARCH/g" "${file}"
852 sed -i "s/%DATE%/$DATE/g" "${file}"
853 sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g" "${file}"
854 sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g" "${file}"
855 sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g" "${file}"
856 sed -i "s/%GRML_NAME%/$GRML_NAME/g" "${file}"
857 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g" "${file}"
858 sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g" "${file}"
859 sed -i "s/%SHORT_NAME%/$SHORT_NAME/g" "${file}"
860 sed -i "s/%VERSION%/$VERSION/g" "${file}"
862 [ -n "$DEFAULT_BOOTOPTIONS" ] && sed -i "s/ boot=live/ boot=live $DEFAULT_BOOTOPTIONS/" "${file}"
864 if [ -n "$NO_BOOTID" ] ; then
865 sed -i "s/ bootid=%BOOTID%//g" "${file}" # drop bootid bootoption
867 sed -i "s/%BOOTID%/$BOOTID/g" "${file}" # adjust bootid=... argument
872 # adjust bootsplash accordingly but make sure the string has the according lenght
873 SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
874 SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
875 for file in f4 f5 ; do
876 if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
877 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
878 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
882 # generate addon list
883 rm -f "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
884 for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
885 include_name=$(basename "$name")
886 echo "include $include_name" >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
889 if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
890 log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
891 echo "include grmlmain.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
892 echo "include default.cfg" > "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
893 echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
894 echo "include grml.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
896 for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
897 echo "include $(basename $f)" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
900 echo "include options.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
901 if [ ! -n "$NO_ADDONS" ] ; then
902 echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
904 echo "include isoprompt.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
905 echo "include hd.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
906 echo "include hidden.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
907 else # assume we are building a custom distribution:
908 log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
909 einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
910 if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
911 log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
913 einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
917 log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
918 echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
919 [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
923 # use old style console based isolinux method only if requested:
924 if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
925 log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
926 einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
927 if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
928 einfo "include for console.cfg already found, nothing to do."
931 log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
932 einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
933 echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
937 log 'Using graphical boot menu.'
938 if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
939 log "include for vesamenu.cfg already found, nothing to do."
941 log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
942 echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
946 if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
947 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
950 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
951 if ! [ -r "$DPKG_LIST" ] ; then
952 ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
954 einfo "Storing package list information as /GRML/${GRML_NAME}-packages.txt on ISO."
955 cp "$DPKG_LIST" "${BUILD_OUTPUT}/GRML/${GRML_NAME}-packages.txt"
959 # autostart for Windows:
960 if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
961 cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
964 FORCE_ISO_REBUILD=true
965 einfo "Finished execution of stage 'boot'" ; eend 0
969 log 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
970 eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
974 # support installation of local files into the chroot/ISO
975 if [ -n "$CHROOT_INSTALL" ] ; then
976 if ! [ -d "$CHROOT_INSTALL" ] ; then
977 log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
978 ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
980 log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
981 einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
982 rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
984 einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
985 FORCE_ISO_REBUILD=true
989 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
990 log "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
991 ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
992 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
993 log "Skipping stage 'squashfs' as requested via option -q or -N"
994 ewarn "Skipping stage 'squashfs' as requested via option -q or -N" ; eend 0
996 [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
997 # make sure we don't leave (even an empty) base.tgz:
998 [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
1000 # if unconfigured default to squashfs-tools' mksquashfs binary
1001 if [ -z "$SQUASHFS_BINARY" ] ; then
1002 SQUASHFS_BINARY='mksquashfs'
1005 if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
1006 log "Using mksquashfs binary ${SQUASHFS_BINARY}"
1007 einfo "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
1009 log "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
1010 eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
1014 # use sane defaults if $SQUASHFS_OPTIONS isn't set
1015 if [ -z "$SQUASHFS_OPTIONS" ] ; then
1016 # use blocksize 256k as this gives best result with regards to time + compression
1017 SQUASHFS_OPTIONS="-b 256k"
1019 # set lzma/xz compression by default, unless -z option has been specified on command line
1020 if [ -z "$SQUASHFS_ZLIB" ] ; then
1021 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp xz"
1023 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp gzip"
1027 # support exclusion of files via exclude-file:
1028 if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
1029 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE -wildcards"
1032 # get rid of unnecessary files when building grml-small for final release:
1033 if echo "$CLASSES" | grep -q GRML_SMALL ; then
1034 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
1038 SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
1040 # informational stuff
1041 [ -n "$SQUASHFS_OPTIONS" ] && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
1042 [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
1043 einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
1045 log "$SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS"
1047 if $SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
1048 -noappend $SQUASHFS_OPTIONS 2>"${SQUASHFS_STDERR}" ; then
1049 echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
1050 log "Finished execution of stage 'squashfs' [$(date)]"
1051 einfo "Finished execution of stage 'squashfs'" ; eend 0
1053 log "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1054 log "$(cat $SQUASHFS_STDERR)"
1055 eerror "Error: there was a critical error executing stage 'squashfs':"
1056 cat "${SQUASHFS_STDERR}"
1061 FORCE_ISO_REBUILD=true
1064 # create md5sum file:
1065 if [ -z "$BOOTSTRAP_ONLY" ] ; then
1066 ( cd $BUILD_OUTPUT/GRML &&
1067 find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1071 # ISO_OUTPUT - mkisofs {{{
1072 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1073 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1075 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1076 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1077 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1078 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1081 # Just until http://bts.grml.org/grml/issue945 has been resolved.
1082 # HYBRID_METHOD defaults to manifold, so make sure the default works OOTB.
1083 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1084 log "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1085 ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1086 HYBRID_METHOD='grub2'
1090 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ] ; then
1091 log "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1092 ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1093 elif [ -n "$SKIP_MKISOFS" ] ; then
1094 log "Skipping stage 'iso build' as requested via option -n or -N"
1095 ewarn "Skipping stage 'iso build' as requested via option -n or -N" ; eend 0
1097 mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1099 if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1100 log "Forcing rebuild of ISO because files on ISO have been modified."
1101 einfo "Forcing rebuild of ISO because files on ISO have been modified."
1104 # support mkisofs as well as genisoimage
1105 if which mkisofs >/dev/null 2>&1; then
1107 elif which genisoimage >/dev/null 2>&1; then
1108 MKISOFS='genisoimage'
1110 log "Error: neither mkisofs nor genisoimage available - can not create ISO."
1111 eerror "Error: neither mkisofs nor genisoimage available - can not create ISO." ; eend 1
1116 if cd "$BUILD_OUTPUT" ; then
1117 if [ "$BOOT_METHOD" = "grub2" ]; then
1118 # make a 2048-byte bootsector for El Torito
1119 dd if=/dev/zero of=boot/grub/toriboot.bin bs=512 count=4 2>/dev/null
1120 # those are in 2048-byte sectors, so 1 16 matches 4 63 below
1121 echo 1 16 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -B 11 | \
1122 dd of=boot/grub/toriboot.bin conv=notrunc 2>/dev/null
1124 log "$MKISOFS -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J $BOOT_ARGS -o ${ISO_OUTPUT}/${ISO_NAME} ."
1125 "$MKISOFS" -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1126 -l -r -J $BOOT_ARGS -no-pad \
1127 -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1128 # both of these need core.img there, so it’s easier to write it here
1129 if [ "$BOOT_METHOD" = "grub2" ] || [ "$HYBRID_METHOD" = "grub2" ]; then
1130 # must be <= 30720 bytes
1131 dd if=boot/grub/core.img of="${ISO_OUTPUT}/${ISO_NAME}" \
1132 conv=notrunc bs=512 seek=4 2>/dev/null
1135 # pad the output ISO to multiples of 256 KiB for partition table support
1136 siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1137 cyls=$((siz / 512 / 32 / 16 + 1)) # C=$cyls H=16 S=32
1138 siz=$((cyls * 16 * 32 * 512)) # size after padding
1139 dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1140 of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1142 # support disabling hybrid ISO image
1143 if [ "$HYBRID_METHOD" = "disable" ] ; then\
1144 log "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1145 einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1147 # use isohybrid only on request
1148 elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
1149 if ! which isohybrid >/dev/null 2>&1 ; then
1150 bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1152 log "Creating hybrid ISO file with isohybrid method"
1153 einfo "Creating hybrid ISO file with isohybrid method"
1154 # Notes for consideration:
1155 # "-entry 4 -type 1c"
1156 # * using 4 as the partition number is supposed to help with BIOSes
1157 # that only support USB-Zip boot
1158 # * using 1c (i.e. hidden FAT32 LBA), instead of the default 0x17
1159 # (hidden NTFS, IIRC), as the partition type is sometimes needed
1160 # to get the BIOS even look at the partition created by isohybrid
1161 isohybrid "${ISO_OUTPUT}/${ISO_NAME}"
1164 # by default use our manifold boot method:
1166 # isoinfo is part of both mkisofs and genisoimage so we're good
1167 bootoff=$(isoinfo -l -i "${ISO_OUTPUT}/${ISO_NAME}" | \
1168 sed -n '/^.*\[ *\([0-9]*\)[] ].* ISOLINUX.BIN;1 *$/s//\1/p')
1169 if ! [ -r boot/grub/core.img ] ; then
1170 ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1171 elif [ "${bootoff:-0}" -lt 1 ] ; then
1172 ewarn "isolinux.bin not found on the ISO file, disabling manifold boot"
1174 log "Creating hybrid ISO file with manifold method"
1175 einfo "Creating hybrid ISO file with manifold method"
1176 if [ "$HYBRID_METHOD" = "grub2" ] ; then
1177 # 512 bytes: MBR, partition table, load GRUB 2
1178 echo 4 63 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 4:0x96 -g $cyls:16:32
1180 # read only one but 2048-byte sized (scale: << 2) sector
1181 echo $bootoff $bootoff | \
1182 mksh /usr/share/grml-live/scripts/bootilnx.mksh -A -M 4:0x96 -g $cyls:16:32 -S 2
1183 fi | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1188 # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1189 case $CLASSES in *RELEASE*)
1192 if cd $ISO_OUTPUT ; then
1193 md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1194 touch -r ${ISO_NAME} ${ISO_NAME}.md5
1195 sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1196 touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1205 if [ "$RC" = 0 ] ; then
1206 log "Finished execution of stage 'iso build' [$(date)]"
1207 einfo "Finished execution of stage 'iso build'" ; eend 0
1209 log "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1210 eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1216 # pack artifacts {{{
1217 if [ -n "$PACK_ARTIFACTS" ]; then
1218 log "Packing artifcats"
1219 einfo "Packing artifacts"
1220 [ -f "${CHROOT_ARCHIVE}" ] && rm -r "${CHROOT_ARCHIVE}"
1221 tar -c -a -f ${CHROOT_ARCHIVE} --preserve-permissions -C "$(dirname ${CHROOT_OUTPUT})" "$(basename ${CHROOT_OUTPUT})"
1226 # log build information to database if grml-live-db is installed and enabled {{{
1228 if [ -d /usr/share/grml-live-db ] ; then
1231 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1232 [ -n "$DPKG_DATABASE" ] || DPKG_DATABASE=/var/log/grml-live.db
1233 [ -n "$DPKG_DBSCRIPT" ] || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1234 [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1236 if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1237 log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1238 eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1242 # disable by default for now, not sure whether really everyone is using a local db file
1243 #if ! touch "$DPKG_DATABASE" ; then
1244 # eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1248 if ! [ -r "$DPKG_LIST" ] ; then
1249 log "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1250 ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1252 einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1253 log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1254 log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1257 if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1273 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1274 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1276 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1278 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1282 ## END OF FILE #################################################################
1283 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2