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
289 # command line parsing {{{
290 while getopts "a:C:c:d:D:g:i:I:o:r:s:t:U:v:AbBFnNquVz" opt; do
293 A) PACK_ARTIFACTS=1 ;;
296 c) CLASSES="$OPTARG" ;;
297 C) CONFIG="$OPTARG" ;;
299 D) GRML_FAI_CONFIG="$OPTARG" ;;
300 g) GRML_NAME="$OPTARG" ;;
301 i) ISO_NAME="$OPTARG" ;;
302 I) CHROOT_INSTALL="$OPTARG" ;;
304 N) BOOTSTRAP_ONLY=1; SKIP_MKISOFS=1; SKIP_MKSQUASHFS=1 ;;
305 o) OUTPUT="$OPTARG" ;;
306 q) SKIP_MKSQUASHFS=1 ;;
307 r) RELEASENAME="$OPTARG" ;;
308 s) SUITE="$OPTARG" ;;
309 t) TEMPLATE_DIRECTORY="$OPTARG";;
310 v) VERSION="$OPTARG" ;;
313 U) CHOWN_USER="$OPTARG" ;;
315 z) SQUASHFS_ZLIB=1 ;;
316 ?) echo "invalid option -$OPTARG" >&2; bailout 1 ;;
319 shift $(($OPTIND - 1)) # set ARGV to the first not parsed commandline parameter
322 # assume sane defaults (if not set already) {{{
323 [ -n "$ARCH" ] || ARCH="$(dpkg --print-architecture)"
324 [ -n "$BOOT_METHOD" ] || BOOT_METHOD='isolinux'
325 [ -n "$CLASSES" ] || CLASSES="GRMLBASE,GRML_MEDIUM,I386"
326 [ -n "$DATE" ] || DATE="$(date +%Y-%m-%d)"
327 [ -n "$DISTRI_INFO" ] || DISTRI_INFO='Grml - Live Linux for system administrators '
328 [ -n "$DISTRI_NAME" ] || DISTRI_NAME="grml"
329 [ -n "$DISTRI_SPLASH" ] || DISTRI_SPLASH='grml.png'
330 [ -n "$FORCE_ISO_REBUILD" ] || FORCE_ISO_REBUILD="false"
331 [ -n "$GRML_FAI_CONFIG" ] || GRML_FAI_CONFIG='/etc/grml/fai'
332 [ -n "$GRML_NAME" ] || GRML_NAME='grml'
333 [ -n "$HOSTNAME" ] || HOSTNAME='grml'
334 [ -n "$HYBRID_METHOD" ] || HYBRID_METHOD='manifold'
335 [ -n "$NFSROOT_CONF" ] || NFSROOT_CONF="${GRML_FAI_CONFIG}/make-fai-nfsroot.conf"
336 [ -n "$RELEASENAME" ] || RELEASENAME='grml-live rocks'
337 [ -n "$SOURCES_LIST_OUTPUT" ] || SOURCES_LIST_OUTPUT="${GRML_FAI_CONFIG}/config/files/etc/apt/sources.list/GRML_LIVE_SOURCES_LIST"
338 [ -n "$SQUASHFS_EXCLUDES_FILE" ] || SQUASHFS_EXCLUDES_FILE="${GRML_FAI_CONFIG}/config/grml/squashfs-excludes"
339 [ -n "$SUITE" ] || SUITE='squeeze'
340 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
341 [ -n "$USERNAME" ] || USERNAME='grml'
342 [ -n "$VERSION" ] || VERSION='0.0.1'
344 # output specific stuff, depends on $OUTPUT (iff not set):
345 [ -n "$OUTPUT" ] || OUTPUT='/grml/grml-live'
346 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
347 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
348 [ -n "$CHROOT_ARCHIVE" ] || CHROOT_ARCHIVE="$OUTPUT/$(basename $CHROOT_OUTPUT).tgz"
349 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
350 [ -n "$LOG_OUTPUT" ] || LOG_OUTPUT="$OUTPUT/grml_logs"
353 # some misc checks before executing FAI {{{
354 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
355 specify it on the command line using the -c option."
356 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
357 specify it on the command line using the -o option."
359 # trim characters that are known to cause problems inside $GRML_NAME;
360 # for example isolinux does not like '-' inside the directory name
361 [ -n "$GRML_NAME" ] && export SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
363 # export variables to have them available in fai scripts:
364 [ -n "$GRML_NAME" ] && export GRML_NAME="$GRML_NAME"
365 [ -n "$RELEASENAME" ] && export RELEASENAME="$RELEASENAME"
368 # ZERO_LOGFILE - check for backwards compatibility reasons {{{
369 # this was default behaviour until grml-live 0.9.34:
370 if [ -n "$ZERO_LOGFILE" ] ; then
371 PRESERVE_LOGFILE='' # make sure it's cleaned then
372 ewarn "Please consider disabling the \$ZERO_LOGFILE option as grml-live clears..."
373 ewarn "... the logfile $LOGFILE by default (unless \$PRESERVE_LOGFILE is set) nowadays."
378 # ask user whether the setup is ok {{{
379 if [ -z "$FORCE" ] ; then
381 echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
383 echo " FAI classes: $CLASSES"
384 [ -r "$LOCAL_CONFIG" ] && echo " Local config: /etc/grml/grml-live.local"
385 [ -n "$CONFIG" ] && echo " Configuration: $CONFIG"
386 [ -n "$GRML_FAI_CONFIG" ] && echo " Config directory: $GRML_FAI_CONFIG"
387 echo " main directory: $OUTPUT"
388 [ -n "$CHROOT_OUTPUT" ] && echo " Chroot target: $CHROOT_OUTPUT"
389 [ -n "$BUILD_OUTPUT" ] && echo " Build target: $BUILD_OUTPUT"
390 [ -n "$ISO_OUTPUT" ] && echo " ISO target: $ISO_OUTPUT"
391 [ -n "$GRML_NAME" ] && echo " Grml name: $GRML_NAME"
392 [ -n "$RELEASENAME" ] && echo " Release name: $RELEASENAME"
393 [ -n "$DATE" ] && echo " Build date: $DATE"
394 [ -n "$VERSION" ] && echo " Grml version: $VERSION"
395 [ -n "$SUITE" ] && echo " Debian suite: $SUITE"
396 [ -n "$ARCH" ] && echo " Architecture: $ARCH"
397 [ -n "$BOOT_METHOD" ] && echo " Boot method: $BOOT_METHOD"
398 [ -n "$HYBRID_METHOD" ] && echo " Hybrid method: $HYBRID_METHOD"
399 [ -n "$TEMPLATE_DIRECTORY" ] && echo " Template files: $TEMPLATE_DIRECTORY"
400 [ -n "$CHROOT_INSTALL" ] && echo " Install files from directory to chroot: $CHROOT_INSTALL"
401 [ -n "$BOOTID" ] && echo " Boot identifier: $BOOTID"
402 [ -n "$NO_BOOTID" ] && echo " Skipping bootid feature."
403 [ -n "$CHOWN_USER" ] && echo " Output owner: $CHOWN_USER"
404 [ -n "$DEFAULT_BOOTOPTIONS" ] && echo " Adding default bootoptions: \"$DEFAULT_BOOTOPTIONS\""
405 [ -n "$FAI_ARGS" ] && echo " Additional arguments for FAI: $FAI_ARGS"
406 [ -n "$LOGFILE" ] && echo " Logging to file: $LOGFILE"
407 [ -n "$SQUASHFS_ZLIB" ] && echo " Using ZLIB (instead of LZMA/XZ) compression."
408 [ -n "$SQUASHFS_OPTIONS" ] && echo " Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
409 [ -n "$VERBOSE" ] && echo " Using VERBOSE mode."
410 [ -n "$PACK_ARTIFACTS" ] && echo " Will prepare packed artifacts and ensure clean build."
411 [ -n "$UPDATE" ] && echo " Executing UPDATE instead of fresh installation."
412 if [ -n "$BOOTSTRAP_ONLY" ] ; then
413 echo " Bootstrapping only and not building (files for) ISO."
415 [ -n "$SKIP_MKSQUASHFS" ] && echo " Skipping creation of SQUASHFS file."
416 [ -n "$SKIP_MKISOFS" ] && echo " Skipping creation of ISO file."
417 [ -n "$BUILD_ONLY" ] && echo " Executing BUILD_ONLY instead of fresh installation or UPDATE."
418 [ -n "$BUILD_DIRTY" ] && echo " Executing BUILD_DIRTY to leave chroot untouched."
421 echo -n "Is this ok for you? [y/N] "
423 if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
424 bailout 1 "Exiting as requested."
430 # clean up before start {{{
431 if [ -n "${PACK_ARTIFACTS}" ]; then
432 echo "Wiping old artifacts"
433 [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && rm -r "${CHROOT_OUTPUT}"
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}"
437 [ -n "${CHROOT_ARCHIVE}" -a -f "${CHROOT_ARCHIVE}" ] && rm "${CHROOT_ARCHIVE}"
441 # create log file {{{
442 [ -n "$LOGFILE" ] || LOGFILE=${LOG_OUTPUT}/grml-live.log
443 mkdir -p $(dirname "${LOGFILE}")
445 chown root:adm $LOGFILE
449 # clean/zero/remove logfiles {{{
451 if [ -n "$PRESERVE_LOGFILE" ] ; then
452 echo "Preserving logfile $LOGFILE as requested via \$PRESERVE_LOGFILE"
454 # make sure it is empty (as it is e.g. appended to grml-live-db)
458 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
459 if [ -d /var/log/fai/"$HOSTNAME" ] ; then
460 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
461 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
462 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
463 rm -f /var/log/fai/"$HOSTNAME"/last \
464 /var/log/fai/"$HOSTNAME"/last-dirinstall \
465 /var/log/fai/"$HOSTNAME"/last-softupdate
470 # source config and startup {{{
471 if [ -n "$CONFIG" ] ; then
472 if ! [ -f "$CONFIG" ] ; then
473 log "Error: $CONFIG could not be read. Exiting. [$(date)]"
474 eerror "Error: $CONFIG could not be read. Exiting." ; eend 1
477 log "Sourcing $CONFIG"
482 start_seconds=$(cut -d . -f 1 /proc/uptime)
483 log "------------------------------------------------------------------------------"
484 log "Starting grml-live [${GRML_LIVE_VERSION}] run on $(date)"
485 if [ -n "$LOCAL_CONFIG" ]; then
486 log "Using local config file: $LOCAL_CONFIG"
488 log "Executed grml-live command line:"
491 einfo "Logging actions to logfile $LOGFILE"
494 # on-the-fly configuration {{{
495 mkdir -p "$(dirname $SOURCES_LIST_OUTPUT)" # might not be present in -D config space
497 cat > "$SOURCES_LIST_OUTPUT" << EOF
498 # NOTE: This file is *NOT* meant for manual customisation! This file is
499 # installed temporarily only by grml-live and will be overriden in the
500 # installation and configuration process then.
503 if [ -n "$MIRROR_DIRECTORY" ] ; then
504 if ! [ -d "$MIRROR_DIRECTORY/debian" ] ; then
505 log "Error: $MIRROR_DIRECTORY/debian does not seem to exist. Exiting. [$(date)]"
506 eerror "Error: $MIRROR_DIRECTORY/debian does not seem to exist. Exiting." ; eend 1
509 echo "$MIRROR_SOURCES" >> "$SOURCES_LIST_OUTPUT"
512 if [ -n "$FAI_DEBOOTSTRAP" ] ; then
513 sed "s#^FAI_DEBOOTSTRAP=.*#FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"#" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
516 # does this suck? YES!
517 # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
519 unstable) SUITE='sid' ;;
520 # make sure that we *NEVER* write any broken suite name to sources.list,
521 # otherwise we won't be able to adjust it one next (correct) execution
529 *) echo "Sorry, $SUITE is not a valid Debian suite, exiting.">&2; bailout 1 ;;
531 export SUITE # make sure it's available in FAI scripts
533 if [ -n "${GRML_LIVE_SOURCES:-}" ] ; then
534 DIST=" etch\| stable\| lenny\| squeeze\| wheezy\| testing\| sid\| unstable"
535 echo "# generated based on \$GRML_LIVE_SOURCES by grml-live
536 $GRML_LIVE_SOURCES" | \
537 sed -e "s/\(^deb .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/;
538 s/\(^deb-src .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/" >> "$SOURCES_LIST_OUTPUT"
540 cat >> "$SOURCES_LIST_OUTPUT" << EOF
541 # generated by grml-live
542 deb http://deb.grml.org/ grml-stable main
543 deb-src http://deb.grml.org/ grml-stable main
545 deb http://deb.grml.org/ grml-testing main
546 deb-src http://deb.grml.org/ grml-testing main
548 deb http://cdn.debian.net/debian $SUITE main contrib non-free
549 deb-src http://cdn.debian.net/debian $SUITE main contrib non-free
553 # notice: activate grml-live pool when building against unstable or testing:
554 if grep -qwe unstable -qwe sid -qwe testing -qwe wheezy "$SOURCES_LIST_OUTPUT" ; then
555 grep -q 'grml-live.*main' "$SOURCES_LIST_OUTPUT" || \
556 grep grml-stable "$SOURCES_LIST_OUTPUT" | \
557 sed 's/grml-stable/grml-live/' >> "$SOURCES_LIST_OUTPUT"
559 grep -q 'grml-live.*main' "$SOURCES_LIST_OUTPUT" && \
560 sed -i 's/.*grml-live.*main/# removed grml-live repository/' "$SOURCES_LIST_OUTPUT"
563 for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" "$NFSROOT_CONF" ; do
564 if [ -n "$file" ] ; then
565 sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
569 # validate whether the specified architecture class matches the
570 # architecture (option), otherwise installation of kernel will fail
571 if echo $CLASSES | grep -qi i386 ; then
572 if ! [[ "$ARCH" == "i386" ]] ; then
573 log "Error: You specified the I386 class but are trying to build something else (AMD64?)."
574 eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
575 eerror "Tip: Either invoke grml-live with '-a i386' or adjust the architecture class. Exiting."
579 elif echo $CLASSES | grep -qi amd64 ; then
580 if ! [[ "$ARCH" == "amd64" ]] ; then
581 log "Error: You specified the AMD64 class but are trying to build something else (I386?)."
582 eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
583 eerror "Tip: Either invoke grml-live with '-a amd64' or adjust the architecture class. Exiting."
589 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
590 sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
592 sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
596 # CHROOT_OUTPUT - execute FAI {{{
597 if [ -n "$BUILD_DIRTY" ]; then
598 log "Skipping stage 'fai' as requested via option -B"
599 ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
601 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
603 # provide inform fai about the ISO we build
604 [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
605 echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
606 [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
607 [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
609 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
610 FAI_ACTION=softupdate
612 FAI_ACTION=dirinstall
615 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
616 if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
617 log "Error: does not look like you have a working chroot. Updating/building not possible."
618 eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
624 if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
625 log "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
626 ewarn "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
628 mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
630 if [ -n "${MIRROR_DIRECTORY}" ] ; then
631 mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
632 mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
635 mkdir -p "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
636 mount --bind "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
638 # tell dpkg to use "unsafe io" during the build
639 [ -d "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d" ] || mkdir -p "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d"
640 echo force-unsafe-io > "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
642 log "Executed FAI command line:"
643 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"
644 BUILD_ONLY="$BUILD_ONLY" BOOTSTRAP_ONLY="$BOOTSTRAP_ONLY" fai $VERBOSE \
645 -C "$GRML_FAI_CONFIG" -s "file:///$GRML_FAI_CONFIG/config" -c"$CLASSES" \
646 -u "$HOSTNAME" "$FAI_ACTION" "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
647 RC="$PIPESTATUS" # notice: bash-only
649 rm -f "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
651 FORCE_ISO_REBUILD=true
653 if [ "$RC" != 0 ] ; then
654 log "Error: critical error while executing fai [exit code ${RC}]. Exiting."
655 eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
658 einfo "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
659 log "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
660 echo "$GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]" > $CHROOT_OUTPUT/etc/grml_version
661 chmod 644 $CHROOT_OUTPUT/etc/grml_version
662 einfo "Rebuilding initramfs"
663 # make sure new /etc/grml_version reaches initramfs, iterate over all
664 # present kernel versions (note: we can't really handle more than one
665 # kernel version anyway right now)
666 # chroot $CHROOT_OUTPUT update-initramfs -u -t => might break when using kernel-package :(
667 for initrd in "$(basename $CHROOT_OUTPUT/boot/vmlinuz-*)" ; do
668 if ! chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -c ; then
669 einfo "Creating fresh initrd did not work, trying update instead:"
670 log "Creating fresh initrd did not work, trying update instead:"
671 chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -u
677 # move fai logs into grml_logs directory
678 mkdir -p "$LOG_OUTPUT"/fai/
679 cp -r "$CHROOT_OUTPUT"/var/log/fai/"$HOSTNAME"/last/* "$LOG_OUTPUT"/fai/
680 chown root:adm "$LOG_OUTPUT"/fai/*
681 chmod 664 "$LOG_OUTPUT"/fai/*
682 rm -rf "$CHROOT_OUTPUT"/var/log/fai
684 # Remove all FAI logs from chroot if class RELEASE is used:
685 rm -f "$CHROOT_OUTPUT"/var/log/install_packages.list
689 # notice: 'fai dirinstall' does not seem to exit appropriate, so:
691 CHECKLOG=/var/log/fai/$HOSTNAME/last
692 if [ -r "$CHECKLOG/software.log" ] ; then
693 # 1 errors during executing of commands
694 grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
695 grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
696 grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
697 grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
698 grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
701 if [ -r "$CHECKLOG/shell.log" ] ; then
702 grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=6
705 if [ -n "$ERROR" ] ; then
706 log "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
707 eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
708 eerror "Note: check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
712 log "Finished execution of stage 'fai dirinstall' [$(date)]"
713 einfo "Finished execution of stage 'fai dirinstall'"
716 einfo "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
717 log "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
723 # package validator {{{
724 CHECKLOG=/var/log/fai/$HOSTNAME/last
726 if [ -r "$CHECKLOG/package_errors.log" ] && grep -q '[a-z]' "$CHECKLOG/package_errors.log" ; then
728 if [ -n "$EXIT_ON_MISSING_PACKAGES" -a -z "$BUILD_DIRTY" ] ; then
729 eerror "The following packages were requested for installation but could not be processed:"
730 cat $CHECKLOG/package_errors.log
731 eerror "... exiting as requested via \$EXIT_ON_MISSING_PACKAGES."
735 ewarn "The following packages were requested for installation but could not be processed:"
736 cat $CHECKLOG/package_errors.log
742 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
743 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
744 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
747 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
748 if [ -n "$BOOTSTRAP_ONLY" ] ; then
749 log "Skipping stage 'boot' as building with bootstrap only."
750 ewarn "Skipping stage 'boot' as building with bootstrap only." ; eend 0
752 if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
753 log "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already."
754 ewarn "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already." ; eend 0
757 [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
758 [ -d "$BUILD_OUTPUT"/boot/"${SHORT_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
760 # if we don't have an initrd we a) can't boot and b) there was an error
761 # during build, so check for the file:
762 INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
763 if [ -n "$INITRD" ] ; then
764 cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.gz
765 find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
767 log "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
768 eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
772 KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
773 if [ -n "$KERNEL_IMAGE" ] ; then
774 cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/linux26
776 log "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
777 eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
781 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
782 if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
783 log "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
784 eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
788 # copy _required_ isolinux files
789 for file in ifcpu64.c32 isolinux.bin vesamenu.c32; do
790 copy_addon_file "${file}" /usr/lib/syslinux isolinux
793 # *always* copy files to output directory so the variables
794 # get adjusted according to the build.
795 cp ${TEMPLATE_DIRECTORY}/boot/isolinux/* "$BUILD_OUTPUT"/boot/isolinux/
797 if [ -n "$NO_ADDONS" ] ; then
798 log "Skipping installation of boot addons as requested via \$NO_ADDONS."
799 einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
801 if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
802 log "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
803 ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
805 # copy addons from system packages or grml-live-compat
806 copy_addon_file ipxe.lkrn /usr/lib/ipxe addons
807 copy_addon_file pci.ids /usr/share/misc addons
808 copy_addon_file memtest86+.bin /boot addons
809 for file in memdisk chain.c32 hdt.c32 menu.c32; do
810 copy_addon_file "${file}" /usr/lib/syslinux addons
813 # make memtest filename FAT16/8.3 compatible
814 mv "${BUILD_OUTPUT}/boot/addons/memtest86+.bin" \
815 "${BUILD_OUTPUT}/boot/addons/memtest"
817 # copy only files so we can handle bsd4grml on its own
818 for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
819 test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
822 if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
823 log "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
824 einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
826 if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
827 cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
829 log "Missing addon file: bsd4grml"
830 ewarn "Missing addon file: bsd4grml" ; eend 0
834 fi # no "$TEMPLATE_DIRECTORY"/boot/addons
837 if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
838 mkdir -p "${BUILD_OUTPUT}/boot/grub"
840 cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
842 if [ -e ${TEMPLATE_DIRECTORY}/compat/grub/linux.mod ]; then
843 cp "${TEMPLATE_DIRECTORY}"/compat/grub/* "${BUILD_OUTPUT}"/boot/grub/
845 if ! which "grub-mkimage" >/dev/null 2>&1 ; then
846 log "grub-mkimage not found, skipping Grub step therefore." ; eend 0
847 ewarn "grub-mkimage not found, skipping Grub step therefore."
848 ewarn "Please install grub-pc-bin or grub-common >= 1.98+20100804-14." ; eend 0
849 elif ! grub-mkimage --help | grep -q -- --format ; then
850 log "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore." ; eend 0
851 ewarn "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore."
852 ewarn "Please install grub-common >= 1.98+20100804-14 or grub-pc-bin." ; eend 0
854 # copy system grub files if grml-live-compat is not installed
855 cp -a /usr/lib/grub/*-pc/*.mod "${BUILD_OUTPUT}"/boot/grub/
856 cp -a /usr/lib/grub/*-pc/*.o "${BUILD_OUTPUT}"/boot/grub/
857 cp -a /usr/lib/grub/*-pc/*.lst "${BUILD_OUTPUT}"/boot/grub/
858 cp -a /usr/share/grub/ascii.pf2 "${BUILD_OUTPUT}"/boot/grub/
859 grub-mkimage -d /usr/lib/grub/*-pc -o \
860 "${BUILD_OUTPUT}/boot/grub/core.img" biosdisk iso9660 --format=i386-pc
864 if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
865 log "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
866 eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
870 [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
871 cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
873 # adjust boot splash information:
874 RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
875 RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
876 RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
878 if [ -r "$BUILD_OUTPUT"/GRML/grml-version ] ; then
879 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
880 sed -i "s/%DATE%/$DATE/" "$BUILD_OUTPUT"/GRML/grml-version
883 # make sure the squashfs filename is set accordingly:
884 SQUASHFS_NAME="$GRML_NAME.squashfs"
886 if [ -n "$NO_BOOTID" ] ; then
887 log 'Skipping bootid feature as requested via $NO_BOOTID.'
888 einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
890 [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
891 [ -d "$BUILD_OUTPUT"/conf ] || mkdir "$BUILD_OUTPUT"/conf
892 einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
893 log "Generating /conf/bootid.txt with entry ${BOOTID}."
894 echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
898 # adjust all variables in the templates with the according distribution information
899 for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
900 "${BUILD_OUTPUT}"/boot/grub/* ; do
901 if [ -r "${file}" ] ; then
902 sed -i "s/%ARCH%/$ARCH/g" "${file}"
903 sed -i "s/%DATE%/$DATE/g" "${file}"
904 sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g" "${file}"
905 sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g" "${file}"
906 sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g" "${file}"
907 sed -i "s/%GRML_NAME%/$GRML_NAME/g" "${file}"
908 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g" "${file}"
909 sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g" "${file}"
910 sed -i "s/%SHORT_NAME%/$SHORT_NAME/g" "${file}"
911 sed -i "s/%VERSION%/$VERSION/g" "${file}"
913 [ -n "$DEFAULT_BOOTOPTIONS" ] && sed -i "s/ boot=live/ boot=live $DEFAULT_BOOTOPTIONS/" "${file}"
915 if [ -n "$NO_BOOTID" ] ; then
916 sed -i "s/ bootid=%BOOTID%//g" "${file}" # drop bootid bootoption
918 sed -i "s/%BOOTID%/$BOOTID/g" "${file}" # adjust bootid=... argument
923 # adjust bootsplash accordingly but make sure the string has the according lenght
924 SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
925 SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
926 for file in f4 f5 ; do
927 if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
928 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
929 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
933 # generate addon list
934 rm -f "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
935 for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
936 include_name=$(basename "$name")
937 echo "include $include_name" >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
940 if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
941 log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
942 echo "include grmlmain.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
943 echo "include default.cfg" > "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
944 echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
945 echo "include grml.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
947 for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
948 echo "include $(basename $f)" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
951 echo "include options.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
952 if [ ! -n "$NO_ADDONS" ] ; then
953 echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
955 echo "include isoprompt.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
956 echo "include hd.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
957 echo "include hidden.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
958 else # assume we are building a custom distribution:
959 log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
960 einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
961 if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
962 log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
964 einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
968 log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
969 echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
970 [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
974 # use old style console based isolinux method only if requested:
975 if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
976 log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
977 einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
978 if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
979 einfo "include for console.cfg already found, nothing to do."
982 log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
983 einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
984 echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
988 log 'Using graphical boot menu.'
989 if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
990 log "include for vesamenu.cfg already found, nothing to do."
992 log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
993 echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
997 if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
998 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
1001 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
1002 if ! [ -r "$DPKG_LIST" ] ; then
1003 ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
1005 einfo "Storing package list information as /GRML/${GRML_NAME}-packages.txt on ISO."
1006 cp "$DPKG_LIST" "${BUILD_OUTPUT}/GRML/${GRML_NAME}-packages.txt"
1010 # autostart for Windows:
1011 if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
1012 cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
1015 FORCE_ISO_REBUILD=true
1016 einfo "Finished execution of stage 'boot'" ; eend 0
1020 log 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
1021 eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
1025 # support installation of local files into the chroot/ISO
1026 if [ -n "$CHROOT_INSTALL" ] ; then
1027 if ! [ -d "$CHROOT_INSTALL" ] ; then
1028 log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1029 ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1031 log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1032 einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1033 rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
1035 einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
1036 FORCE_ISO_REBUILD=true
1040 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
1041 log "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
1042 ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
1043 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
1044 log "Skipping stage 'squashfs' as requested via option -q or -N"
1045 ewarn "Skipping stage 'squashfs' as requested via option -q or -N" ; eend 0
1047 [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
1048 # make sure we don't leave (even an empty) base.tgz:
1049 [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
1051 # if unconfigured default to squashfs-tools' mksquashfs binary
1052 if [ -z "$SQUASHFS_BINARY" ] ; then
1053 SQUASHFS_BINARY='mksquashfs'
1056 if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
1057 log "Using mksquashfs binary ${SQUASHFS_BINARY}"
1058 einfo "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
1060 log "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
1061 eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
1065 # use sane defaults if $SQUASHFS_OPTIONS isn't set
1066 if [ -z "$SQUASHFS_OPTIONS" ] ; then
1067 # use blocksize 256k as this gives best result with regards to time + compression
1068 SQUASHFS_OPTIONS="-b 256k"
1070 # set lzma/xz compression by default, unless -z option has been specified on command line
1071 if [ -z "$SQUASHFS_ZLIB" ] ; then
1072 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp xz"
1074 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp gzip"
1078 # support exclusion of files via exclude-file:
1079 if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
1080 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE -wildcards"
1083 # get rid of unnecessary files when building grml-small for final release:
1084 if echo "$CLASSES" | grep -q GRML_SMALL ; then
1085 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
1089 SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
1091 # informational stuff
1092 [ -n "$SQUASHFS_OPTIONS" ] && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
1093 [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
1094 einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
1096 log "$SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS"
1098 if $SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
1099 -noappend $SQUASHFS_OPTIONS 2>"${SQUASHFS_STDERR}" ; then
1100 echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
1101 log "Finished execution of stage 'squashfs' [$(date)]"
1102 einfo "Finished execution of stage 'squashfs'" ; eend 0
1104 log "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1105 log "$(cat $SQUASHFS_STDERR)"
1106 eerror "Error: there was a critical error executing stage 'squashfs':"
1107 cat "${SQUASHFS_STDERR}"
1112 FORCE_ISO_REBUILD=true
1115 # create md5sum file:
1116 if [ -z "$BOOTSTRAP_ONLY" ] ; then
1117 ( cd $BUILD_OUTPUT/GRML &&
1118 find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1122 # ISO_OUTPUT - mkisofs {{{
1123 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1124 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1126 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1127 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1128 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1129 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1132 # Just until http://bts.grml.org/grml/issue945 has been resolved.
1133 # HYBRID_METHOD defaults to manifold, so make sure the default works OOTB.
1134 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1135 log "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1136 ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1137 HYBRID_METHOD='grub2'
1141 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ] ; then
1142 log "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1143 ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1144 elif [ -n "$SKIP_MKISOFS" ] ; then
1145 log "Skipping stage 'iso build' as requested via option -n or -N"
1146 ewarn "Skipping stage 'iso build' as requested via option -n or -N" ; eend 0
1148 mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1150 if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1151 log "Forcing rebuild of ISO because files on ISO have been modified."
1152 einfo "Forcing rebuild of ISO because files on ISO have been modified."
1155 # support mkisofs as well as genisoimage
1156 if which mkisofs >/dev/null 2>&1; then
1158 elif which genisoimage >/dev/null 2>&1; then
1159 MKISOFS='genisoimage'
1161 log "Error: neither mkisofs nor genisoimage available - can not create ISO."
1162 eerror "Error: neither mkisofs nor genisoimage available - can not create ISO." ; eend 1
1167 if cd "$BUILD_OUTPUT" ; then
1168 if [ "$BOOT_METHOD" = "grub2" ]; then
1169 # make a 2048-byte bootsector for El Torito
1170 dd if=/dev/zero of=boot/grub/toriboot.bin bs=512 count=4 2>/dev/null
1171 # those are in 2048-byte sectors, so 1 16 matches 4 63 below
1172 echo 1 16 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -B 11 | \
1173 dd of=boot/grub/toriboot.bin conv=notrunc 2>/dev/null
1175 log "$MKISOFS -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J $BOOT_ARGS -o ${ISO_OUTPUT}/${ISO_NAME} ."
1176 "$MKISOFS" -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1177 -l -r -J $BOOT_ARGS -no-pad \
1178 -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1179 # both of these need core.img there, so it’s easier to write it here
1180 if [ "$BOOT_METHOD" = "grub2" ] || [ "$HYBRID_METHOD" = "grub2" ]; then
1181 # must be <= 30720 bytes
1182 dd if=boot/grub/core.img of="${ISO_OUTPUT}/${ISO_NAME}" \
1183 conv=notrunc bs=512 seek=4 2>/dev/null
1186 # pad the output ISO to multiples of 256 KiB for partition table support
1187 siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1188 cyls=$((siz / 512 / 32 / 16 + 1)) # C=$cyls H=16 S=32
1189 siz=$((cyls * 16 * 32 * 512)) # size after padding
1190 dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1191 of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1193 # support disabling hybrid ISO image
1194 if [ "$HYBRID_METHOD" = "disable" ] ; then\
1195 log "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1196 einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1198 # use isohybrid only on request
1199 elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
1200 if ! which isohybrid >/dev/null 2>&1 ; then
1201 bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1203 log "Creating hybrid ISO file with isohybrid method"
1204 einfo "Creating hybrid ISO file with isohybrid method"
1205 # Notes for consideration:
1206 # "-entry 4 -type 1c"
1207 # * using 4 as the partition number is supposed to help with BIOSes
1208 # that only support USB-Zip boot
1209 # * using 1c (i.e. hidden FAT32 LBA), instead of the default 0x17
1210 # (hidden NTFS, IIRC), as the partition type is sometimes needed
1211 # to get the BIOS even look at the partition created by isohybrid
1212 isohybrid "${ISO_OUTPUT}/${ISO_NAME}"
1215 # by default use our manifold boot method:
1217 # isoinfo is part of both mkisofs and genisoimage so we're good
1218 bootoff=$(isoinfo -l -i "${ISO_OUTPUT}/${ISO_NAME}" | \
1219 sed -n '/^.*\[ *\([0-9]*\)[] ].* ISOLINUX.BIN;1 *$/s//\1/p')
1220 if ! [ -r boot/grub/core.img ] ; then
1221 ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1222 elif [ "${bootoff:-0}" -lt 1 ] ; then
1223 ewarn "isolinux.bin not found on the ISO file, disabling manifold boot"
1225 log "Creating hybrid ISO file with manifold method"
1226 einfo "Creating hybrid ISO file with manifold method"
1227 if [ "$HYBRID_METHOD" = "grub2" ] ; then
1228 # 512 bytes: MBR, partition table, load GRUB 2
1229 echo 4 63 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 4:0x96 -g $cyls:16:32
1231 # read only one but 2048-byte sized (scale: << 2) sector
1232 echo $bootoff $bootoff | \
1233 mksh /usr/share/grml-live/scripts/bootilnx.mksh -A -M 4:0x96 -g $cyls:16:32 -S 2
1234 fi | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1239 # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1240 case $CLASSES in *RELEASE*)
1243 if cd $ISO_OUTPUT ; then
1244 md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1245 touch -r ${ISO_NAME} ${ISO_NAME}.md5
1246 sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1247 touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1256 if [ "$RC" = 0 ] ; then
1257 log "Finished execution of stage 'iso build' [$(date)]"
1258 einfo "Finished execution of stage 'iso build'" ; eend 0
1260 log "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1261 eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1267 # pack artifacts {{{
1268 if [ -n "$PACK_ARTIFACTS" ]; then
1269 log "Packing artifcats"
1270 einfo "Packing artifacts"
1271 [ -f "${CHROOT_ARCHIVE}" ] && rm -r "${CHROOT_ARCHIVE}"
1272 tar -c -a -f ${CHROOT_ARCHIVE} --preserve-permissions -C "$(dirname ${CHROOT_OUTPUT})" "$(basename ${CHROOT_OUTPUT})"
1277 # log build information to database if grml-live-db is installed and enabled {{{
1279 if [ -d /usr/share/grml-live-db ] ; then
1282 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1283 [ -n "$DPKG_DATABASE" ] || DPKG_DATABASE=/var/log/grml-live.db
1284 [ -n "$DPKG_DBSCRIPT" ] || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1285 [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1287 if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1288 log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1289 eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1293 # disable by default for now, not sure whether really everyone is using a local db file
1294 #if ! touch "$DPKG_DATABASE" ; then
1295 # eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1299 if ! [ -r "$DPKG_LIST" ] ; then
1300 log "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1301 ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1303 einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1304 log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1305 log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1308 if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1324 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1325 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1327 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1329 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1333 ## END OF FILE #################################################################
1334 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2