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
26 # The line following this line is patched by debian/rules.
27 GRML_LIVE_VERSION='***UNRELEASED***'
32 ADDONS_LIST_FILE='/boot/isolinux/addons_list.cfg'
35 # usage information {{{
39 $PN - build process script for generating a (grml based) Linux Live-ISO
41 Usage: $PN [options, see as follows]
43 -a <architecture> architecture; available values: i386 and amd64
44 -A clean build directories before and after running
45 -b build the ISO without updating the chroot via FAI
46 -B build the ISO without touching the chroot (skips cleanup)
47 -c <classe[s]> classes to be used for building the ISO via FAI
48 -C <configfile> configuration file for grml-live
49 -d <date> use specified date instead of build time as date of release
50 -D <configdir> use specified configuration directory instead of /etc/grml/fai
51 -e <iso_name> extract ISO and squashfs contents from iso_name
52 -F force execution without prompting
53 -g <grml_name> set the grml flavour name
54 -h display short usage information and exit
55 -i <iso_name> name of ISO
56 -I <src_directory> directory which provides files that should become
57 part of the chroot/ISO
58 -n skip generation of ISO
59 -N bootstrap (build chroot) only, do not create files for ISO
60 -o <output_directory> main output directory of the build process
62 -Q skip netboot package build
63 -r <release_name> release name
64 -s <suite> Debian suite; values: etch, lenny, squeeze, sid
65 -t <template_directory> place of the templates
66 -u update existing chroot instead of rebuilding it from scratch
67 -U <username> arrange output to be owned by specified username
68 -v <version_number> specify version number of the release
69 -V increase verbosity in the build process
70 -z use ZLIB instead of LZMA/XZ compression
75 $PN -c GRMLBASE,GRML_FULL,AMD64 -o /dev/shm/grml
76 $PN -c GRMLBASE,GRML_FULL,AMD64 -i grml_0.0-1.iso -v 0.0-1
77 $PN -c GRMLBASE,GRML_FULL,AMD64 -s sid -V -r 'grml-live rocks'
79 More details: man grml-live + /usr/share/doc/grml-live/grml-live.html
80 http://grml.org/grml-live/
82 Please send your bug reports and feedback to the grml-team: http://grml.org/bugs/
86 # make sure it's possible to get usage information without being
87 # root or actually executing the script
88 if [ "$1" = '-h' -o "$1" = '--help' ] ; then
90 [ "$(id -u 2>/dev/null)" != 0 ] && echo "Please notice that this script requires root permissions."
95 # some runtime checks {{{
96 # we need root permissions for the build-process:
97 if [ "$(id -u 2>/dev/null)" != 0 ] ; then
98 echo "Error: please run this script with uid 0 (root)." >&2
102 if [ -r /var/run/fai/FAI_INSTALLATION_IN_PROGRESS ] ; then
103 echo "/usr/sbin/fai already running or was aborted before.">&2
104 echo "You may remove /var/run/fai/FAI_INSTALLATION_IN_PROGRESS and try again.">&2
109 if [ -r /var/run/fai/fai_softupdate_is_running ] ; then
110 echo "/usr/sbin/fai softupdate already running or was aborted before.">&2
111 echo "You may remove /var/run/fai/fai_softupdate_is_running and try again.">&2
116 # lsb-functions and configuration stuff {{{
117 # make sure they are not set by default
128 # don't use colors/escape sequences
129 if [ -r /lib/lsb/init-functions ] ; then
130 . /lib/lsb/init-functions
131 ! log_use_fancy_output && NOCOLORS=true
134 if [ -r /etc/grml/lsb-functions ] ; then
135 . /etc/grml/lsb-functions
137 einfo() { echo " [*] $*" ;}
138 eerror() { echo " [!] $*">&2 ;}
139 ewarn() { echo " [x] $*" ;}
141 eindent() { return 0 ;}
142 eoutdent() { return 0 ;}
145 # source main configuration file:
146 LIVE_CONF=/etc/grml/grml-live.conf
150 # umount all directories {{{
152 # make sure we don't leave any mounts - FAI doesn't remove them always
153 umount $CHROOT_OUTPUT/proc/sys/fs/binfmt_misc 2>/dev/null || /bin/true
154 umount $CHROOT_OUTPUT/proc 2>/dev/null || /bin/true
155 umount $CHROOT_OUTPUT/sys 2>/dev/null || /bin/true
156 umount $CHROOT_OUTPUT/dev/pts 2>/dev/null || /bin/true
157 umount $CHROOT_OUTPUT/dev 2>/dev/null || /bin/true
159 # certain FAI versions sadly leave a ramdisk behind, so better safe than sorry
160 if [ -x /usr/lib/fai/mkramdisk ] ; then
161 /usr/lib/fai/mkramdisk -u "$(readlink -f ${CHROOT_OUTPUT}/var/lib/dpkg)" >/dev/null 2>&1 || /bin/true
164 umount "${CHROOT_OUTPUT}/grml-live/sources/" 2>/dev/null || /bin/true
165 [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
171 rm -f /var/run/fai/fai_softupdate_is_running \
172 /var/run/fai/FAI_INSTALLATION_IN_PROGRESS
173 [ -n "$CONFIGDUMP" ] && rm -f "$CONFIGDUMP"
174 [ -n "$SQUASHFS_STDERR" ] && rm -rf "$SQUASHFS_STDERR"
176 [ -n "$1" ] && EXIT="$1" || EXIT="1"
177 [ -n "$2" ] && eerror "$2">&2
178 if [ -n "$CLEAN_ARTIFACTS" ]; then
181 [ -n "${BUILD_OUTPUT}" -a -d "${BUILD_OUTPUT}" ] && rm -r "${BUILD_OUTPUT}"
182 [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && rm -r "${CHROOT_OUTPUT}"
185 if [ -n "$CHOWN_USER" ]; then
186 log "Setting ownership"
187 einfo "Setting ownership"
188 [ -n "${OUTPUT}" -a -d "${OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${OUTPUT}"
189 [ -n "${BUILD_OUTPUT}" -a -d "${BUILD_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${BUILD_OUTPUT}"
190 [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${CHROOT_OUTPUT}"
191 [ -n "${ISO_OUTPUT}" -a -d "${ISO_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${ISO_OUTPUT}"
192 [ -n "${LOG_OUTPUT}" -a -d "${LOG_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${LOG_OUTPUT}"
193 [ -n "${NETBOOT}" -a -d "${NETBOOT}" ] && chown -R "${CHOWN_USER}:" "${NETBOOT}"
196 log "------------------------------------------------------------------------------"
199 trap bailout 1 2 3 3 6 9 14 15
203 # some important functions {{{
206 # usage: log "string to log"
207 log() { [ -n "$LOGFILE" ] && echo "$*" >> $LOGFILE ; }
209 # cut string at character number int = $1
210 # usage: cut_string 5 "1234567890" will output "12345"
212 [ -n "$2" ] || return 1
213 echo "$2" | head -c "$1"; echo -ne "\n"
216 # prepend int = $1 spaces before string = $2
217 # usage: extend_string_begin 5 "123" will output " 123"
218 extend_string_begin() {
219 [ -n "$2" ] || return 1
220 local COUNT="$(echo $2 | wc -c)"
221 local FILL="$(expr $COUNT - $1)"
222 while [ "$FILL" -gt 1 ] ; do
224 local FILL=$(expr $FILL - 1)
226 while [ "$FILL" -lt 1 ] ; do
228 local FILL=$(expr $FILL + 1)
230 echo "$2" | head -c "$1"; echo -ne "\n"
233 # append int = $1 spaces to string = $2
234 # usage: extend_string_begin 5 "123" will output "123 "
235 extend_string_end() {
236 [ -n "$2" ] || return 1
237 echo -n "$2" | head -c "$1"
238 local COUNT="$(echo $2 | wc -c)"
239 local FILL="$(expr $COUNT - $1)"
240 while [ "$FILL" -gt 1 ] ; do
242 local FILL=$(expr $FILL - 1)
244 while [ "$FILL" -lt 1 ] ; do
246 local FILL=$(expr $FILL + 1)
251 # Copy addonfile $1 from either
252 # * the chroot (via $2, the system path),
253 # * or from TEMPLATE_DIRECTORY/compat (if exists),
254 # * or from the host system (again, using $2),
255 # or warn about the missing file.
258 # * We assume that the chroot always has a "good" version of
259 # the file. Also it makes sources handling easier.
260 # * On unstable, we Recommend the Debian packages containing
261 # these files. The user can override them by putting his
262 # "better" version into the chroot.
263 # * On stable, the Debian packages are probably not available,
264 # or outdated, so we look in TEMPLATE_DIRECTORY/compat first, where
265 # our grml-live-compat package installs current file versions.
267 DEST="${BUILD_OUTPUT}/boot/$3"
268 if [ ! -d "${DEST}/" ]; then
271 if [ -e "$CHROOT_OUTPUT/$2/$1" ]; then
272 log "Copying $1 from chroot"
273 cp "$CHROOT_OUTPUT/$2/$1" "${DEST}/"
276 if [ -e "${TEMPLATE_DIRECTORY}/compat/$3/$1" ]; then
277 log "Copying $1 from grml-live-compat"
278 cp "${TEMPLATE_DIRECTORY}/compat/$3/$1" "${DEST}/"
281 if [ -e "$2/$1" ]; then
282 log "Copying $1 from system"
283 cp "$2/$1" "${DEST}/"
287 msg="Missing addon file: \"$1\""
288 ewarn "$msg" ; eend 1
289 log "copy_addon_file: $msg"
293 # command line parsing {{{
294 while getopts "a:C:c:d:D:e:g:i:I:o:r:s:t:U:v:AbBFnNqQuVz" opt; do
297 A) CLEAN_ARTIFACTS=1 ;;
300 c) CLASSES="$OPTARG" ;;
301 C) LOCAL_CONFIG="$(readlink -f $OPTARG)" ;;
303 D) GRML_FAI_CONFIG="$(readlink -f $OPTARG)" ;;
304 e) EXTRACT_ISO_NAME="$(readlink -f $OPTARG)" ;;
305 g) GRML_NAME="$OPTARG" ;;
306 i) ISO_NAME="$OPTARG" ;;
307 I) CHROOT_INSTALL="$OPTARG" ;;
309 N) BOOTSTRAP_ONLY=1; SKIP_MKISOFS=1; SKIP_MKSQUASHFS=1 ;;
310 o) OUTPUT="$(readlink -f $OPTARG)" ;;
311 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 # read local (non-packaged) configuration {{{
329 if [ -z "$LOCAL_CONFIG" ]; then
330 if [ -r "/etc/grml/grml-live.local" ]; then
331 LOCAL_CONFIG="/etc/grml/grml-live.local"
334 if [ -n "$LOCAL_CONFIG" ]; then
335 if [ -r "$LOCAL_CONFIG" ]; then
338 eerror "Could not read specified local configuration file \"$LOCAL_CONFIG\"."
341 LOCAL_CONFIG=$(readlink -f "$LOCAL_CONFIG")
346 if [ -n "${GRML_LIVE_SOURCES:-}" ] ; then
347 eerror "Config variable \$GRML_LIVE_SOURCES is set. This variable has been deprecated."
348 ewarn "Please set up \${GRML_FAI_CONFIG}/config/files/etc/apt/sources.list.d/* instead."
353 # assume sane defaults (if not set already) {{{
354 [ -n "$ARCH" ] || ARCH="$(dpkg --print-architecture)"
355 [ -n "$BOOT_METHOD" ] || BOOT_METHOD='isolinux'
356 [ -n "$CLASSES" ] || CLASSES="GRMLBASE,GRML_FULL,$(echo ${ARCH} | tr 'a-z' 'A-Z')"
357 [ -n "$DATE" ] || DATE="$(date +%Y-%m-%d)"
358 [ -n "$DISTRI_INFO" ] || DISTRI_INFO='Grml - Live Linux for system administrators'
359 [ -n "$DISTRI_NAME" ] || DISTRI_NAME="grml"
360 [ -n "$DISTRI_SPLASH" ] || DISTRI_SPLASH='grml.png'
361 [ -n "$FORCE_ISO_REBUILD" ] || FORCE_ISO_REBUILD="false"
362 [ -n "$GRML_FAI_CONFIG" ] || GRML_FAI_CONFIG='/etc/grml/fai'
363 [ -n "$GRML_NAME" ] || GRML_NAME='grml'
364 [ -n "$HOSTNAME" ] || HOSTNAME='grml'
365 [ -n "$HYBRID_METHOD" ] || HYBRID_METHOD='manifold'
366 [ -n "$NFSROOT_CONF" ] || NFSROOT_CONF="${GRML_FAI_CONFIG}/make-fai-nfsroot.conf"
367 [ -n "$RELEASENAME" ] || RELEASENAME='grml-live rocks'
368 [ -n "$SQUASHFS_EXCLUDES_FILE" ] || SQUASHFS_EXCLUDES_FILE="${GRML_FAI_CONFIG}/config/grml/squashfs-excludes"
369 [ -n "$SUITE" ] || SUITE='squeeze'
370 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
371 [ -n "$USERNAME" ] || USERNAME='grml'
372 [ -n "$VERSION" ] || VERSION='0.0.1'
374 # output specific stuff, depends on $OUTPUT (iff not set):
375 [ -n "$OUTPUT" ] || OUTPUT='/grml/grml-live'
376 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
377 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
378 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
379 [ -n "$LOG_OUTPUT" ] || LOG_OUTPUT="$OUTPUT/grml_logs"
380 [ -n "$REPORTS" ] || REPORTS="${LOG_OUTPUT}/reports/"
381 [ -n "$NETBOOT" ] || NETBOOT="${OUTPUT}/netboot/"
384 # some misc checks before executing FAI {{{
385 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
386 specify it on the command line using the -c option."
387 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
388 specify it on the command line using the -o option."
390 # trim characters that are known to cause problems inside $GRML_NAME;
391 # for example isolinux does not like '-' inside the directory name
392 [ -n "$GRML_NAME" ] && export SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
394 # export variables to have them available in fai scripts:
395 [ -n "$GRML_NAME" ] && export GRML_NAME="$GRML_NAME"
396 [ -n "$RELEASENAME" ] && export RELEASENAME="$RELEASENAME"
399 # ZERO_LOGFILE - check for backwards compatibility reasons {{{
400 # this was default behaviour until grml-live 0.9.34:
401 if [ -n "$ZERO_LOGFILE" ] ; then
402 PRESERVE_LOGFILE='' # make sure it's cleaned then
403 ewarn "Please consider disabling the \$ZERO_LOGFILE option as grml-live clears..."
404 ewarn "... the logfile $LOGFILE by default (unless \$PRESERVE_LOGFILE is set) nowadays."
409 # ask user whether the setup is ok {{{
410 if [ -z "$FORCE" ] ; then
412 echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
414 echo " FAI classes: $CLASSES"
415 [ -n "$LOCAL_CONFIG" ] && echo " Configuration: $LOCAL_CONFIG"
416 [ -n "$GRML_FAI_CONFIG" ] && echo " Config directory: $GRML_FAI_CONFIG"
417 echo " main directory: $OUTPUT"
418 [ -n "$EXTRACT_ISO_NAME" ] && echo " Extract ISO: $EXTRACT_ISO_NAME"
419 [ -n "$CHROOT_OUTPUT" ] && echo " Chroot target: $CHROOT_OUTPUT"
420 [ -n "$BUILD_OUTPUT" ] && echo " Build target: $BUILD_OUTPUT"
421 [ -n "$ISO_OUTPUT" ] && echo " ISO target: $ISO_OUTPUT"
422 [ -n "$GRML_NAME" ] && echo " Grml name: $GRML_NAME"
423 [ -n "$RELEASENAME" ] && echo " Release name: $RELEASENAME"
424 [ -n "$DATE" ] && echo " Build date: $DATE"
425 [ -n "$VERSION" ] && echo " Grml version: $VERSION"
426 [ -n "$SUITE" ] && echo " Debian suite: $SUITE"
427 [ -n "$ARCH" ] && echo " Architecture: $ARCH"
428 [ -n "$BOOT_METHOD" ] && echo " Boot method: $BOOT_METHOD"
429 [ -n "$HYBRID_METHOD" ] && echo " Hybrid method: $HYBRID_METHOD"
430 [ -n "$TEMPLATE_DIRECTORY" ] && echo " Template files: $TEMPLATE_DIRECTORY"
431 [ -n "$CHROOT_INSTALL" ] && echo " Install files from directory to chroot: $CHROOT_INSTALL"
432 [ -n "$BOOTID" ] && echo " Boot identifier: $BOOTID"
433 [ -n "$NO_BOOTID" ] && echo " Skipping bootid feature."
434 [ -n "$CHOWN_USER" ] && echo " Output owner: $CHOWN_USER"
435 [ -n "$DEFAULT_BOOTOPTIONS" ] && echo " Adding default bootoptions: \"$DEFAULT_BOOTOPTIONS\""
436 [ -n "$FAI_ARGS" ] && echo " Additional arguments for FAI: $FAI_ARGS"
437 [ -n "$LOGFILE" ] && echo " Logging to file: $LOGFILE"
438 [ -n "$SQUASHFS_ZLIB" ] && echo " Using ZLIB (instead of LZMA/XZ) compression."
439 [ -n "$SQUASHFS_OPTIONS" ] && echo " Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
440 [ -n "$VERBOSE" ] && echo " Using VERBOSE mode."
441 [ -n "$CLEAN_ARTIFACTS" ] && echo " Will clean output before and after running."
442 [ -n "$UPDATE" ] && echo " Executing UPDATE instead of fresh installation."
443 if [ -n "$BOOTSTRAP_ONLY" ] ; then
444 echo " Bootstrapping only and not building (files for) ISO."
446 [ -n "$SKIP_MKSQUASHFS" ] && echo " Skipping creation of SQUASHFS file."
447 [ -n "$SKIP_NETBOOT" ] && echo " Skipping creation of NETBOOT package."
448 [ -n "$SKIP_MKISOFS" ] && echo " Skipping creation of ISO file."
449 [ -n "$BUILD_ONLY" ] && echo " Executing BUILD_ONLY instead of fresh installation or UPDATE."
450 [ -n "$BUILD_DIRTY" ] && echo " Executing BUILD_DIRTY to leave chroot untouched."
453 echo -n "Is this ok for you? [y/N] "
455 if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
456 bailout 1 "Exiting as requested."
462 # clean up before start {{{
463 if [ -n "${CLEAN_ARTIFACTS}" ]; then
464 echo "Wiping old artifacts"
465 [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && rm -r "${CHROOT_OUTPUT}"
466 [ -n "${BUILD_OUTPUT}" -a -d "${BUILD_OUTPUT}" ] && rm -r "${BUILD_OUTPUT}"
467 [ -n "${ISO_OUTPUT}" -a -d "${ISO_OUTPUT}" ] && rm -r "${ISO_OUTPUT}"
468 [ -n "${LOG_OUTPUT}" -a -d "${LOG_OUTPUT}" ] && rm -r "${LOG_OUTPUT}"
469 [ -n "${NETBOOT}" -a -d "${NETBOOT}" ] && rm -r "${NETBOOT}"
473 # create log file {{{
474 [ -n "$LOGFILE" ] || LOGFILE=${LOG_OUTPUT}/grml-live.log
475 mkdir -p $(dirname "${LOGFILE}")
477 chown root:adm $LOGFILE
481 # clean/zero/remove logfiles {{{
483 if [ -n "$PRESERVE_LOGFILE" ] ; then
484 echo "Preserving logfile $LOGFILE as requested via \$PRESERVE_LOGFILE"
486 # make sure it is empty (as it is e.g. appended to grml-live-db)
490 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
491 if [ -d /var/log/fai/"$HOSTNAME" ] ; then
492 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
493 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
494 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
495 rm -f /var/log/fai/"$HOSTNAME"/last \
496 /var/log/fai/"$HOSTNAME"/last-dirinstall \
497 /var/log/fai/"$HOSTNAME"/last-softupdate
502 # source config and startup {{{
503 if [ -n "$CONFIG" ] ; then
504 if ! [ -f "$CONFIG" ] ; then
505 log "Error: $CONFIG could not be read. Exiting. [$(date)]"
506 eerror "Error: $CONFIG could not be read. Exiting." ; eend 1
509 log "Sourcing $CONFIG"
514 start_seconds=$(cut -d . -f 1 /proc/uptime)
515 log "------------------------------------------------------------------------------"
516 log "Starting grml-live [${GRML_LIVE_VERSION}] run on $(date)"
517 log "Using local config file: $LOCAL_CONFIG"
518 log "Executed grml-live command line:"
521 einfo "Logging actions to logfile $LOGFILE"
524 # dump config variables into file, for script access {{{
527 '^(GRML_NAME|RELEASENAME|DATE|VERSION|SUITE|ARCH|DISTRI_NAME|USERNAME|HOSTNAME|APT_PROXY)=' \
531 # unpack iso/squashfs {{{
533 if [ -n "$EXTRACT_ISO_NAME" ]; then
534 log "Unpacking ISO from ${EXTRACT_ISO_NAME}"
535 einfo "Unpacking ISO from ${EXTRACT_ISO_NAME}"
536 local mountpoint=$(mktemp -d)
538 mount -o loop "${EXTRACT_ISO_NAME}" "$mountpoint" ; rc=$?
539 if [ "$rc" != 0 ]; then
542 eerror "mount failed"
546 unsquashfs -d "${CHROOT_OUTPUT}" "${mountpoint}"/live/*/*.squashfs ; rc=$?
549 if [ "$rc" != 0 ]; then
550 log "unsquashfs failed"
551 eerror "unsquashfs failed"
560 # on-the-fly configuration {{{
561 if [ -n "$FAI_DEBOOTSTRAP" ] ; then
562 sed "s#^FAI_DEBOOTSTRAP=.*#FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"#" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
565 # does this suck? YES!
566 # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
568 unstable) SUITE='sid' ; CLASSES="DEBIAN_UNSTABLE,$CLASSES" ;;
569 *) CLASSES="DEBIAN_$(echo $SUITE | tr 'a-z' 'A-Z'),$CLASSES";;
571 export SUITE # make sure it's available in FAI scripts
573 for file in "$LIVE_CONF" "$LOCAL_CONFIG" "$NFSROOT_CONF" ; do
574 if [ -n "$file" ] ; then
575 sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
579 # validate whether the specified architecture class matches the
580 # architecture (option), otherwise installation of kernel will fail
581 if echo $CLASSES | grep -qi i386 ; then
582 if ! [[ "$ARCH" == "i386" ]] ; then
583 log "Error: You specified the I386 class but are trying to build something else (AMD64?)."
584 eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
585 eerror "Tip: Either invoke grml-live with '-a i386' or adjust the architecture class. Exiting."
589 elif echo $CLASSES | grep -qi amd64 ; then
590 if ! [[ "$ARCH" == "amd64" ]] ; then
591 log "Error: You specified the AMD64 class but are trying to build something else (I386?)."
592 eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
593 eerror "Tip: Either invoke grml-live with '-a amd64' or adjust the architecture class. Exiting."
599 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
600 sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
602 sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
606 # CHROOT_OUTPUT - execute FAI {{{
607 if [ -n "$BUILD_DIRTY" ]; then
608 log "Skipping stage 'fai' as requested via option -B"
609 ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
611 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
613 # provide inform fai about the ISO we build
614 [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
615 echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
616 [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
617 [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
619 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
620 FAI_ACTION=softupdate
622 FAI_ACTION=dirinstall
625 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
626 if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
627 log "Error: does not look like you have a working chroot. Updating/building not possible."
628 eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
634 if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
635 log "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
636 ewarn "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
638 mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
640 if [ -n "${MIRROR_DIRECTORY}" ] ; then
641 mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
642 mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
645 mkdir -p "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
646 mount --bind "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
648 # tell dpkg to use "unsafe io" during the build
649 [ -d "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d" ] || mkdir -p "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d"
650 echo force-unsafe-io > "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
652 log "Executed FAI command line:"
653 log "BUILD_ONLY=$BUILD_ONLY BOOTSTRAP_ONLY=$BOOTSTRAP_ONLY GRML_LIVE_CONFIG=$CONFIGDUMP fai $VERBOSE -C $GRML_FAI_CONFIG -s file:///$GRML_FAI_CONFIG/config -c$CLASSES -u $HOSTNAME $FAI_ACTION $CHROOT_OUTPUT $FAI_ARGS"
654 BUILD_ONLY="$BUILD_ONLY" BOOTSTRAP_ONLY="$BOOTSTRAP_ONLY" GRML_LIVE_CONFIG="$CONFIGDUMP" fai $VERBOSE \
655 -C "$GRML_FAI_CONFIG" -s "file:///$GRML_FAI_CONFIG/config" -c"$CLASSES" \
656 -u "$HOSTNAME" "$FAI_ACTION" "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
657 RC="$PIPESTATUS" # notice: bash-only
659 rm -f "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
661 FORCE_ISO_REBUILD=true
663 if [ "$RC" != 0 ] ; then
664 log "Error: critical error while executing fai [exit code ${RC}]. Exiting."
665 eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
669 # move fai logs into grml_logs directory
670 mkdir -p "$LOG_OUTPUT"/fai/
671 cp -r "$CHROOT_OUTPUT"/var/log/fai/"$HOSTNAME"/last/* "$LOG_OUTPUT"/fai/
672 rm -rf "$CHROOT_OUTPUT"/var/log/fai
673 # copy fai package list
674 cp "$CHROOT_OUTPUT"/var/log/install_packages.list "$LOG_OUTPUT"/fai/
676 chown root:adm "$LOG_OUTPUT"/fai/*
677 chmod 664 "$LOG_OUTPUT"/fai/*
681 # notice: 'fai dirinstall' does not seem to exit appropriate, so:
683 CHECKLOG="$LOG_OUTPUT"/fai/
684 if [ -r "$CHECKLOG/software.log" ] ; then
685 # 1 errors during executing of commands
686 grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
687 grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
688 grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
689 grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
690 grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
693 if [ -r "$CHECKLOG/shell.log" ] ; then
694 grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=6
697 if [ -n "$ERROR" ] ; then
698 log "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
699 eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
700 eerror "Note: check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
704 log "Finished execution of stage 'fai dirinstall' [$(date)]"
705 einfo "Finished execution of stage 'fai dirinstall'"
711 # package validator {{{
712 CHECKLOG=/var/log/fai/$HOSTNAME/last
713 if [ -r "$CHECKLOG/dpkg.selections" ] ; then
714 package_count=$(wc -l "$CHECKLOG/dpkg.selections" | awk '{print $1}')
716 package_count="unknown"
720 REPORT_MISSING_PACKAGES="${REPORTS}/TEST-MissingPackages.xml"
722 # check for missing packages
723 if ! [ -s "$CHECKLOG/package_errors.log" ] ; then
724 einfo "No missing packages found, generating empty junit report."
726 cat > "${REPORT_MISSING_PACKAGES}" << EOF
727 <?xml version="1.0" encoding="UTF-8"?>
728 <testsuite name="grml-live-missing-packages" tests="${package_count}" time="1" failures="0" errors="0" skipped="0" assertions="0">
729 <testcase name="test_missing_packages" time="0" assertions="0">
739 einfo "Missing packages found, generating junit report."
741 if [ -r "$CHECKLOG/package_errors.log" ] ; then
742 package_errors=$(wc -l "$CHECKLOG/package_errors.log" | awk '{print $1}')
744 package_errors="unknown"
748 REPORT_MISSING_PACKAGES="${REPORTS}/TEST-MissingPackages.xml"
750 cat > "${REPORT_MISSING_PACKAGES}" << EOF
751 <?xml version="1.0" encoding="UTF-8"?>
752 <testsuite name="grml-live-missing-packages" tests="${package_count}" time="1" failures="${package_errors}" errors="${package_errors}" skipped="0" assertions="0">
755 for package in $(awk '{print $5}' "${CHECKLOG}/package_errors.log" | sed 's/\.$//') ; do
756 cat >> "${REPORT_MISSING_PACKAGES}" << EOF
757 <testcase name="test_missing_packages_${package}" time="0" assertions="0">
758 <failure type="RuntimeError" message="Package ${package} is missing">
759 Package $package is missing in chroot
765 cat >> "${REPORT_MISSING_PACKAGES}" << EOF
774 if [ -n "$EXIT_ON_MISSING_PACKAGES" -a -z "$BUILD_DIRTY" ] ; then
775 eerror "The following packages were requested for installation but could not be processed:"
776 cat "$CHECKLOG/package_errors.log"
777 eerror "... exiting as requested via \$EXIT_ON_MISSING_PACKAGES."
781 ewarn "The following packages were requested for installation but could not be processed:"
782 cat "$CHECKLOG/package_errors.log"
788 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
789 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
790 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
793 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
794 if [ -n "$BOOTSTRAP_ONLY" ] ; then
795 log "Skipping stage 'boot' as building with bootstrap only."
796 ewarn "Skipping stage 'boot' as building with bootstrap only." ; eend 0
798 if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
799 log "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already."
800 ewarn "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already." ; eend 0
803 [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
804 [ -d "$BUILD_OUTPUT"/boot/"${SHORT_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
806 # if we don't have an initrd we a) can't boot and b) there was an error
807 # during build, so check for the file:
808 INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
809 if [ -n "$INITRD" ] ; then
810 cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.img
811 find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
813 log "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
814 eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
818 KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
819 if [ -n "$KERNEL_IMAGE" ] ; then
820 cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/vmlinuz
822 log "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
823 eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
828 if [ -r "${CHROOT_OUTPUT}/boot/efi.img" -a -r "${CHROOT_OUTPUT}/boot/bootx64.efi" ] ; then
829 einfo "Moving EFI boot files into ISO path."
830 log "Moving EFI boot files into ISO path."
832 mv "${CHROOT_OUTPUT}/boot/efi.img" "${BUILD_OUTPUT}/boot/" || RC=$?
833 mkdir -p "${BUILD_OUTPUT}/efi/boot/" || RC=$?
834 mv "${CHROOT_OUTPUT}/boot/bootx64.efi" "${BUILD_OUTPUT}/efi/boot/bootx64.efi" || RC=$?
838 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
839 if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
840 log "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
841 eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
845 # copy _required_ isolinux files
846 for file in ifcpu64.c32 isolinux.bin vesamenu.c32; do
847 copy_addon_file "${file}" /usr/lib/syslinux isolinux
850 # *always* copy files to output directory so the variables
851 # get adjusted according to the build.
852 cp ${TEMPLATE_DIRECTORY}/boot/isolinux/* "$BUILD_OUTPUT"/boot/isolinux/
854 if [ -n "$NO_ADDONS" ] ; then
855 log "Skipping installation of boot addons as requested via \$NO_ADDONS."
856 einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
858 if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
859 log "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
860 ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
862 # copy addons from system packages or grml-live-compat
863 copy_addon_file ipxe.lkrn /usr/lib/ipxe addons
864 copy_addon_file pci.ids /usr/share/misc addons
865 copy_addon_file memtest86+.bin /boot addons
866 for file in memdisk chain.c32 hdt.c32 menu.c32; do
867 copy_addon_file "${file}" /usr/lib/syslinux addons
870 # make memtest filename FAT16/8.3 compatible
871 mv "${BUILD_OUTPUT}/boot/addons/memtest86+.bin" \
872 "${BUILD_OUTPUT}/boot/addons/memtest"
874 # copy only files so we can handle bsd4grml on its own
875 for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
876 test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
879 if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
880 log "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
881 einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
883 if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
884 cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
886 log "Missing addon file: bsd4grml"
887 ewarn "Missing addon file: bsd4grml" ; eend 0
891 fi # no "$TEMPLATE_DIRECTORY"/boot/addons
894 if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
895 mkdir -p "${BUILD_OUTPUT}/boot/grub"
897 cp -a ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
899 # copy grub files from target
900 cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/*-pc/*.mod "${BUILD_OUTPUT}"/boot/grub/
901 cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/*-pc/*.o "${BUILD_OUTPUT}"/boot/grub/
902 cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/*-pc/*.lst "${BUILD_OUTPUT}"/boot/grub/
903 cp -a "${CHROOT_OUTPUT}"/usr/share/grub/ascii.pf2 "${BUILD_OUTPUT}"/boot/grub/
904 cp -a "${CHROOT_OUTPUT}"/boot/grub/core.img "${BUILD_OUTPUT}"/boot/grub/
905 cp -a "${CHROOT_OUTPUT}"/boot/grub/grub.img "${BUILD_OUTPUT}"/boot/grub/
907 if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
908 log "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
909 eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
913 mkdir -p "$BUILD_OUTPUT"/GRML/"${GRML_NAME}"/
914 cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/"${GRML_NAME}"/
916 # adjust boot splash information:
917 RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
918 RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
919 RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
921 if [ -r "$BUILD_OUTPUT"/GRML/"${GRML_NAME}"/grml-version ] ; then
922 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/"${GRML_NAME}"/grml-version
923 sed -i "s/%DATE%/$DATE/" "$BUILD_OUTPUT"/GRML/"${GRML_NAME}"/grml-version
926 # make sure the squashfs filename is set accordingly:
927 SQUASHFS_NAME="$GRML_NAME.squashfs"
929 if [ -n "$NO_BOOTID" ] ; then
930 log 'Skipping bootid feature as requested via $NO_BOOTID.'
931 einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
933 [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
934 [ -d "$BUILD_OUTPUT"/conf ] || mkdir "$BUILD_OUTPUT"/conf
935 einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
936 log "Generating /conf/bootid.txt with entry ${BOOTID}."
937 echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
941 # adjust all variables in the templates with the according distribution information
942 for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
943 "${BUILD_OUTPUT}"/boot/grub/* ; do
944 if [ -r "${file}" ] && [ -f "${file}" ] ; then
945 sed -i "s/%ARCH%/$ARCH/g" "${file}"
946 sed -i "s/%DATE%/$DATE/g" "${file}"
947 sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g" "${file}"
948 sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g" "${file}"
949 sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g" "${file}"
950 sed -i "s/%GRML_NAME%/$GRML_NAME/g" "${file}"
951 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g" "${file}"
952 sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g" "${file}"
953 sed -i "s/%SHORT_NAME%/$SHORT_NAME/g" "${file}"
954 sed -i "s/%VERSION%/$VERSION/g" "${file}"
956 [ -n "$DEFAULT_BOOTOPTIONS" ] && sed -i "s/ boot=live/ boot=live $DEFAULT_BOOTOPTIONS/" "${file}"
958 if [ -n "$NO_BOOTID" ] ; then
959 sed -i "s/ bootid=%BOOTID%//g" "${file}" # drop bootid bootoption
961 sed -i "s/%BOOTID%/$BOOTID/g" "${file}" # adjust bootid=... argument
966 for param in ARCH DATE DISTRI_INFO DISTRI_NAME DISTRI_SPLASH GRML_NAME SQUASHFS_NAME \
967 RELEASE_INFO SHORT_NAME VERSION ; do
968 for file in $(find "${BUILD_OUTPUT}" -name "*%$param%*") ; do
969 value="$(eval echo '$'"$param")"
970 mv ${file} ${file/\%${param}\%/$value}
974 # adjust bootsplash accordingly but make sure the string has the according lenght
975 SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
976 SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
977 for file in f4 f5 ; do
978 if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
979 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
980 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
984 # generate addon list
985 rm -f "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
986 for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
987 include_name=$(basename "$name")
988 echo "include $include_name" >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
991 if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
992 log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
993 echo "include grmlmain.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
994 echo "include default.cfg" > "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
995 echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
996 echo "include grml.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
998 for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
999 echo "include $(basename $f)" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1002 echo "include options.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1003 if [ ! -n "$NO_ADDONS" ] ; then
1004 echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1006 echo "include isoprompt.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1007 echo "include hd.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1008 echo "include hidden.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1009 else # assume we are building a custom distribution:
1010 log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
1011 einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
1012 if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
1013 log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
1015 einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
1019 log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1020 echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1021 [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1025 # use old style console based isolinux method only if requested:
1026 if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
1027 log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
1028 einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
1029 if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
1030 einfo "include for console.cfg already found, nothing to do."
1033 log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1034 einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1035 echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1039 log 'Using graphical boot menu.'
1040 if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
1041 log "include for vesamenu.cfg already found, nothing to do."
1043 log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1044 echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1048 if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
1049 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
1052 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
1053 if ! [ -r "$DPKG_LIST" ] ; then
1054 ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
1056 einfo "Storing package list information as /GRML/${GRML_NAME}/packages.txt on ISO."
1057 cp "$DPKG_LIST" "${BUILD_OUTPUT}"/GRML/"${GRML_NAME}"/packages.txt
1061 # autostart for Windows:
1062 if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
1063 cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
1066 FORCE_ISO_REBUILD=true
1067 einfo "Finished execution of stage 'boot'" ; eend 0
1071 log 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
1072 eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
1076 # support installation of local files into the chroot/ISO
1077 if [ -n "$CHROOT_INSTALL" ] ; then
1078 if ! [ -d "$CHROOT_INSTALL" ] ; then
1079 log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1080 ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1082 log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1083 einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1084 rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
1086 einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
1087 FORCE_ISO_REBUILD=true
1091 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
1092 log "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
1093 ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
1094 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
1095 log "Skipping stage 'squashfs' as requested via option -q or -N"
1096 ewarn "Skipping stage 'squashfs' as requested via option -q or -N" ; eend 0
1098 mkdir -p "$BUILD_OUTPUT"/live/"${GRML_NAME}"/
1099 # make sure we don't leave (even an empty) base.tgz:
1100 [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
1102 # if unconfigured default to squashfs-tools' mksquashfs binary
1103 if [ -z "$SQUASHFS_BINARY" ] ; then
1104 SQUASHFS_BINARY='mksquashfs'
1107 if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
1108 log "Using mksquashfs binary ${SQUASHFS_BINARY}"
1109 einfo "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
1111 log "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
1112 eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
1116 # use sane defaults if $SQUASHFS_OPTIONS isn't set
1117 if [ -z "$SQUASHFS_OPTIONS" ] ; then
1118 # use blocksize 256k as this gives best result with regards to time + compression
1119 SQUASHFS_OPTIONS="-b 256k"
1121 # set lzma/xz compression by default, unless -z option has been specified on command line
1122 if [ -z "$SQUASHFS_ZLIB" ] ; then
1123 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp xz"
1125 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp gzip"
1129 # support exclusion of files via exclude-file:
1130 if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
1131 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE -wildcards"
1134 # get rid of unnecessary files when building grml-small for final release:
1135 if echo "$CLASSES" | grep -q GRML_SMALL ; then
1136 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
1140 SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
1142 # informational stuff
1143 [ -n "$SQUASHFS_OPTIONS" ] && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
1144 [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
1145 einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
1147 log "$SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/${GRML_NAME}/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS"
1149 if $SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/"${GRML_NAME}"/"${GRML_NAME}".squashfs \
1150 -noappend $SQUASHFS_OPTIONS 2>"${SQUASHFS_STDERR}" ; then
1151 echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/"${GRML_NAME}"/filesystem.module
1152 log "Finished execution of stage 'squashfs' [$(date)]"
1153 einfo "Finished execution of stage 'squashfs'" ; eend 0
1155 log "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1156 log "$(cat $SQUASHFS_STDERR)"
1157 eerror "Error: there was a critical error executing stage 'squashfs':"
1158 cat "${SQUASHFS_STDERR}"
1163 FORCE_ISO_REBUILD=true
1166 # create md5sum file:
1167 if [ -z "$BOOTSTRAP_ONLY" ] ; then
1168 ( cd $BUILD_OUTPUT/GRML/"${GRML_NAME}" &&
1169 find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1173 # ISO_OUTPUT - mkisofs {{{
1174 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1175 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1177 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1178 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1179 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1180 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1183 # Just until http://bts.grml.org/grml/issue945 has been resolved.
1184 # HYBRID_METHOD defaults to manifold, so make sure the default works OOTB.
1185 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1186 log "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1187 ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1188 HYBRID_METHOD='grub2'
1192 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ] ; then
1193 log "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1194 ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1195 elif [ -n "$SKIP_MKISOFS" ] ; then
1196 log "Skipping stage 'iso build' as requested via option -n or -N"
1197 ewarn "Skipping stage 'iso build' as requested via option -n or -N" ; eend 0
1199 mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1201 if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1202 log "Forcing rebuild of ISO because files on ISO have been modified."
1203 einfo "Forcing rebuild of ISO because files on ISO have been modified."
1206 # support xorriso as well mkisofs and genisoimage
1207 if which xorriso >/dev/null 2>&1 ; then
1208 MKISOFS='xorriso -as mkisofs'
1209 elif which mkisofs >/dev/null 2>&1; then
1211 elif which genisoimage >/dev/null 2>&1; then
1212 MKISOFS='genisoimage'
1214 log "Error: neither xorriso nor mkisofs nor genisoimage available - can not create ISO."
1215 eerror "Error: neither xorriso nor mkisofs nor genisoimage available - can not create ISO." ; eend 1
1219 einfo "Using ${MKISOFS} to build ISO." ; eend 0
1220 case "${ARCH}-${MKISOFS}" in
1221 # using -eltorito-alt-boot is limited to xorriso for now
1225 if ! dpkg --compare-versions $(dpkg-query -W -f='${Version}\n' xorriso 2>/dev/null) gt-nl 1.1.6-1 ; then
1226 log "Disabling (U)EFI boot support because xorriso version is too old."
1227 ewarn "Disabling (U)EFI boot support because xorriso version is too old." ; eend 0
1229 if [ -r "${BUILD_OUTPUT}"/boot/efi.img ] ; then
1230 einfo "Enabling (U)EFI boot."
1231 log "Enabling (U)EFI boot."
1232 BOOT_ARGS="$BOOT_ARGS -boot-info-table -eltorito-alt-boot -e boot/efi.img -no-emul-boot"
1235 log "Disabling (U)EFI boot support because /boot/efi.img is missing."
1236 ewarn "Disabling (U)EFI boot support because /boot/efi.img is missing." ; eend 0
1245 if cd "$BUILD_OUTPUT" ; then
1246 if [ "$BOOT_METHOD" = "grub2" ]; then
1247 # make a 2048-byte bootsector for El Torito
1248 dd if=/dev/zero of=boot/grub/toriboot.bin bs=512 count=4 2>/dev/null
1249 # those are in 2048-byte sectors, so 1 16 matches 4 63 below
1250 echo 1 16 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -B 11 | \
1251 dd of=boot/grub/toriboot.bin conv=notrunc 2>/dev/null
1253 log "$MKISOFS -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J $BOOT_ARGS -o ${ISO_OUTPUT}/${ISO_NAME} ."
1254 $MKISOFS -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1255 -l -r -J $BOOT_ARGS -no-pad \
1256 -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1257 # both of these need core.img there, so it’s easier to write it here
1258 if [ "$BOOT_METHOD" = "grub2" ] || [ "$HYBRID_METHOD" = "grub2" ]; then
1259 # must be <= 30720 bytes
1260 dd if=boot/grub/core.img of="${ISO_OUTPUT}/${ISO_NAME}" \
1261 conv=notrunc bs=512 seek=4 2>/dev/null
1264 # pad the output ISO to multiples of 256 KiB for partition table support
1265 siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1266 cyls=$((siz / 512 / 32 / 16 + 1)) # C=$cyls H=16 S=32
1267 siz=$((cyls * 16 * 32 * 512)) # size after padding
1268 dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1269 of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1271 # support disabling hybrid ISO image
1272 if [ "$HYBRID_METHOD" = "disable" ] ; then\
1273 log "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1274 einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1276 elif [ "$HYBRID_METHOD" = "manifold" ] ; then
1277 # isoinfo is part of both mkisofs and genisoimage so we're good
1278 bootoff=$(isoinfo -l -i "${ISO_OUTPUT}/${ISO_NAME}" | \
1279 sed -n '/^.*\[ *\([0-9]*\)[] ].* ISOLINUX.BIN[;1]* *$/s//\1/p')
1280 if ! [ -r boot/grub/core.img ] ; then
1281 ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1282 elif [ "${bootoff:-0}" -lt 1 ] ; then
1283 ewarn "isolinux.bin not found on the ISO file, disabling manifold boot"
1285 log "Creating hybrid ISO file with manifold method"
1286 einfo "Creating hybrid ISO file with manifold method"
1287 if [ "$HYBRID_METHOD" = "grub2" ] ; then
1288 # 512 bytes: MBR, partition table, load GRUB 2
1289 echo 4 63 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 4:0x96 -g $cyls:16:32
1291 # read only one but 2048-byte sized (scale: << 2) sector
1292 echo $bootoff $bootoff | \
1293 mksh /usr/share/grml-live/scripts/bootilnx.mksh -A -M 4:0x96 -g $cyls:16:32 -S 2
1294 fi | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1297 # use isohybrid as default
1299 if ! which isohybrid >/dev/null 2>&1 ; then
1300 bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1302 log "Creating hybrid ISO file with isohybrid method"
1303 einfo "Creating hybrid ISO file with isohybrid method"
1304 # Notes for consideration:
1305 # "-entry 4 -type 1c"
1306 # * using 4 as the partition number is supposed to help with BIOSes
1307 # that only support USB-Zip boot
1308 # * using 1c (i.e. hidden FAT32 LBA), instead of the default 0x17
1309 # (hidden NTFS, IIRC), as the partition type is sometimes needed
1310 # to get the BIOS even look at the partition created by isohybrid
1311 if isohybrid --help | grep -q -- --uefi ; then
1312 einfo "Detected uefi support for isohybrid, enabling."
1313 ISOHYBRID_OPTIONS=--uefi
1316 log "isohybrid $ISOHYBRID_OPTIONS ${ISO_OUTPUT}/${ISO_NAME}"
1317 isohybrid $ISOHYBRID_OPTIONS "${ISO_OUTPUT}/${ISO_NAME}"
1322 # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1323 case $CLASSES in *RELEASE*)
1326 if cd $ISO_OUTPUT ; then
1327 md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1328 touch -r ${ISO_NAME} ${ISO_NAME}.md5
1329 sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1330 touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1339 if [ "$RC" = 0 ] ; then
1340 log "Finished execution of stage 'iso build' [$(date)]"
1341 einfo "Finished execution of stage 'iso build'" ; eend 0
1343 log "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1344 eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1350 # netboot package {{{
1351 create_netbootpackage() {
1352 local OUTPUT_FILE="${NETBOOT}/grml_netboot_package_${GRML_NAME}_${VERSION}.tar.bz2"
1354 if [ -f "${OUTPUT_FILE}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
1355 log "Skipping stage 'netboot' as $OUTPUT_FILE exists already."
1356 ewarn "Skipping stage 'netboot' as $OUTPUT_FILE exists already." ; eend 0
1358 elif [ -n "$SKIP_NETBOOT" ] ; then
1359 log "Skipping stage 'netboot' as requested via option -Q"
1360 ewarn "Skipping stage 'netboot' as requested via option -Q" ; eend 0
1366 if ! [ -r "${CHROOT}/usr/lib/syslinux/pxelinux.0" ] ; then
1367 ewarn "File /usr/lib/syslinux/pxelinux.0 not found in build chroot." ; eend 0
1369 einfo "Install syslinux[-common] package in chroot to get a netboot package."
1374 local OUTPUTDIR="${NETBOOT}/build_tmp"
1375 local WORKING_DIR="${OUTPUTDIR}/grml_netboot_package_${GRML_NAME}_${VERSION}/tftpboot/"
1377 mkdir -p "$WORKING_DIR"
1379 cp "${CHROOT_OUTPUT}"/boot/vmlinuz-* "$WORKING_DIR"/vmlinuz
1380 cp "${CHROOT_OUTPUT}"/boot/initrd.img-* "$WORKING_DIR"/initrd.img
1381 cp "${CHROOT_OUTPUT}"/usr/lib/syslinux/pxelinux.0 "${WORKING_DIR}/pxelinux.0"
1383 mkdir -p "${WORKING_DIR}/pxelinux.cfg"
1384 if [ -r "${BUILD_OUTPUT}/boot/isolinux/netboot.cfg" ] ; then
1385 cp "${BUILD_OUTPUT}/boot/isolinux/netboot.cfg" "${WORKING_DIR}/pxelinux.cfg/default"
1387 ewarn "File ${BUILD_OUTPUT}/boot/isolinux/netboot.cfg not found." ; eend 0
1390 if tar -C "$OUTPUTDIR" -jcf "${OUTPUT_FILE}" "grml_netboot_package_${GRML_NAME}_${VERSION}" ; then
1391 sha1sum "${OUTPUT_FILE}" > "${OUTPUT_FILE}.sha1"
1392 einfo "Generated netboot package ${OUTPUT_FILE}" ; eend 0
1393 rm -rf "${OUTPUTDIR}"
1395 rm -rf "${OUTPUTDIR}"
1396 eerror "Could not generate netboot package ${OUTPUT_FILE}" ; eend 1
1401 create_netbootpackage
1404 # log build information to database if grml-live-db is installed and enabled {{{
1406 if [ -d /usr/share/grml-live-db ] ; then
1409 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1410 [ -n "$DPKG_DATABASE" ] || DPKG_DATABASE=/var/log/grml-live.db
1411 [ -n "$DPKG_DBSCRIPT" ] || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1412 [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1414 if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1415 log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1416 eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1420 # disable by default for now, not sure whether really everyone is using a local db file
1421 #if ! touch "$DPKG_DATABASE" ; then
1422 # eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1426 if ! [ -r "$DPKG_LIST" ] ; then
1427 log "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1428 ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1430 einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1431 log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1432 log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1435 if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1451 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1452 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1454 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1456 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1460 ## END OF FILE #################################################################
1461 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2