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/run 2>/dev/null || /bin/true
156 umount $CHROOT_OUTPUT/sys 2>/dev/null || /bin/true
157 umount $CHROOT_OUTPUT/dev/pts 2>/dev/null || /bin/true
158 umount $CHROOT_OUTPUT/dev 2>/dev/null || /bin/true
160 # certain FAI versions sadly leave a ramdisk behind, so better safe than sorry
161 if [ -x /usr/lib/fai/mkramdisk ] ; then
162 /usr/lib/fai/mkramdisk -u "$(readlink -f ${CHROOT_OUTPUT}/var/lib/dpkg)" >/dev/null 2>&1 || /bin/true
165 umount "${CHROOT_OUTPUT}/grml-live/sources/" 2>/dev/null || /bin/true
166 [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
172 rm -f /var/run/fai/fai_softupdate_is_running \
173 /var/run/fai/FAI_INSTALLATION_IN_PROGRESS
174 [ -n "$CONFIGDUMP" ] && rm -f "$CONFIGDUMP"
175 [ -n "$SQUASHFS_STDERR" ] && rm -rf "$SQUASHFS_STDERR"
177 [ -n "$1" ] && EXIT="$1" || EXIT="1"
178 [ -n "$2" ] && eerror "$2">&2
179 if [ -n "$CLEAN_ARTIFACTS" ]; then
182 [ -n "${BUILD_OUTPUT}" -a -d "${BUILD_OUTPUT}" ] && rm -r "${BUILD_OUTPUT}"
183 [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && rm -r "${CHROOT_OUTPUT}"
186 if [ -n "$CHOWN_USER" ]; then
187 log "Setting ownership"
188 einfo "Setting ownership"
189 [ -n "${OUTPUT}" -a -d "${OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${OUTPUT}"
190 [ -n "${BUILD_OUTPUT}" -a -d "${BUILD_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${BUILD_OUTPUT}"
191 [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${CHROOT_OUTPUT}"
192 [ -n "${ISO_OUTPUT}" -a -d "${ISO_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${ISO_OUTPUT}"
193 [ -n "${LOG_OUTPUT}" -a -d "${LOG_OUTPUT}" ] && chown -R "${CHOWN_USER}:" "${LOG_OUTPUT}"
194 [ -n "${NETBOOT}" -a -d "${NETBOOT}" ] && chown -R "${CHOWN_USER}:" "${NETBOOT}"
197 log "------------------------------------------------------------------------------"
200 trap bailout 1 2 3 3 6 9 14 15
204 # some important functions {{{
207 # usage: log "string to log"
208 log() { [ -n "$LOGFILE" ] && echo "$*" >> $LOGFILE ; }
210 # cut string at character number int = $1
211 # usage: cut_string 5 "1234567890" will output "12345"
213 [ -n "$2" ] || return 1
214 echo "$2" | head -c "$1"; echo -ne "\n"
217 # prepend int = $1 spaces before string = $2
218 # usage: extend_string_begin 5 "123" will output " 123"
219 extend_string_begin() {
220 [ -n "$2" ] || return 1
221 local COUNT="$(echo $2 | wc -c)"
222 local FILL="$(expr $COUNT - $1)"
223 while [ "$FILL" -gt 1 ] ; do
225 local FILL=$(expr $FILL - 1)
227 while [ "$FILL" -lt 1 ] ; do
229 local FILL=$(expr $FILL + 1)
231 echo "$2" | head -c "$1"; echo -ne "\n"
234 # append int = $1 spaces to string = $2
235 # usage: extend_string_begin 5 "123" will output "123 "
236 extend_string_end() {
237 [ -n "$2" ] || return 1
238 echo -n "$2" | head -c "$1"
239 local COUNT="$(echo $2 | wc -c)"
240 local FILL="$(expr $COUNT - $1)"
241 while [ "$FILL" -gt 1 ] ; do
243 local FILL=$(expr $FILL - 1)
245 while [ "$FILL" -lt 1 ] ; do
247 local FILL=$(expr $FILL + 1)
252 # Copy addonfile $1 from either
253 # * the chroot (via $2, the system path),
254 # * or from TEMPLATE_DIRECTORY/compat (if exists),
255 # * or from the host system (again, using $2),
256 # or warn about the missing file.
259 # * We assume that the chroot always has a "good" version of
260 # the file. Also it makes sources handling easier.
261 # * On unstable, we Recommend the Debian packages containing
262 # these files. The user can override them by putting his
263 # "better" version into the chroot.
264 # * On stable, the Debian packages are probably not available,
265 # or outdated, so we look in TEMPLATE_DIRECTORY/compat first, where
266 # our grml-live-compat package installs current file versions.
268 DEST="${BUILD_OUTPUT}/boot/$3"
269 if [ ! -d "${DEST}/" ]; then
272 if [ -e "$CHROOT_OUTPUT/$2/$1" ]; then
273 log "Copying $1 from chroot"
274 cp "$CHROOT_OUTPUT/$2/$1" "${DEST}/"
277 if [ -e "${TEMPLATE_DIRECTORY}/compat/$3/$1" ]; then
278 log "Copying $1 from grml-live-compat"
279 cp "${TEMPLATE_DIRECTORY}/compat/$3/$1" "${DEST}/"
282 if [ -e "$2/$1" ]; then
283 log "Copying $1 from system"
284 cp "$2/$1" "${DEST}/"
288 msg="Missing addon file: \"$1\""
289 ewarn "$msg" ; eend 1
290 log "copy_addon_file: $msg"
294 # command line parsing {{{
295 while getopts "a:C:c:d:D:e:g:i:I:o:r:s:t:U:v:AbBFnNqQuVz" opt; do
298 A) CLEAN_ARTIFACTS=1 ;;
301 c) CLASSES="$OPTARG" ;;
302 C) LOCAL_CONFIG="$(readlink -f $OPTARG)" ;;
304 D) GRML_FAI_CONFIG="$(readlink -f $OPTARG)" ;;
305 e) EXTRACT_ISO_NAME="$(readlink -f $OPTARG)" ;;
306 g) GRML_NAME="$OPTARG" ;;
307 i) ISO_NAME="$OPTARG" ;;
308 I) CHROOT_INSTALL="$OPTARG" ;;
310 N) BOOTSTRAP_ONLY=1; SKIP_MKISOFS=1; SKIP_MKSQUASHFS=1 ;;
311 o) OUTPUT="$(readlink -f $OPTARG)" ;;
312 q) SKIP_MKSQUASHFS=1 ;;
314 r) RELEASENAME="$OPTARG" ;;
315 s) SUITE="$OPTARG" ;;
316 t) TEMPLATE_DIRECTORY="$OPTARG";;
317 v) VERSION="$OPTARG" ;;
320 U) CHOWN_USER="$OPTARG" ;;
322 z) SQUASHFS_ZLIB=1 ;;
323 ?) echo "invalid option -$OPTARG" >&2; bailout 1 ;;
326 shift $(($OPTIND - 1)) # set ARGV to the first not parsed commandline parameter
329 # read local (non-packaged) configuration {{{
330 if [ -z "$LOCAL_CONFIG" ]; then
331 if [ -r "/etc/grml/grml-live.local" ]; then
332 LOCAL_CONFIG="/etc/grml/grml-live.local"
335 if [ -n "$LOCAL_CONFIG" ]; then
336 if [ -r "$LOCAL_CONFIG" ]; then
339 eerror "Could not read specified local configuration file \"$LOCAL_CONFIG\"."
342 LOCAL_CONFIG=$(readlink -f "$LOCAL_CONFIG")
347 if [ -n "${GRML_LIVE_SOURCES:-}" ] ; then
348 eerror "Config variable \$GRML_LIVE_SOURCES is set. This variable has been deprecated."
349 ewarn "Please set up \${GRML_FAI_CONFIG}/config/files/etc/apt/sources.list.d/* instead."
354 # assume sane defaults (if not set already) {{{
355 [ -n "$ARCH" ] || ARCH="$(dpkg --print-architecture)"
356 [ -n "$BOOT_METHOD" ] || BOOT_METHOD='isolinux'
357 [ -n "$CLASSES" ] || CLASSES="GRMLBASE,GRML_FULL,$(echo ${ARCH} | tr 'a-z' 'A-Z')"
358 [ -n "$DATE" ] || DATE="$(date +%Y-%m-%d)"
359 [ -n "$DISTRI_INFO" ] || DISTRI_INFO='Grml - Live Linux for system administrators'
360 [ -n "$DISTRI_NAME" ] || DISTRI_NAME="grml"
361 [ -n "$DISTRI_SPLASH" ] || DISTRI_SPLASH='grml.png'
362 [ -n "$FORCE_ISO_REBUILD" ] || FORCE_ISO_REBUILD="false"
363 [ -n "$GRML_FAI_CONFIG" ] || GRML_FAI_CONFIG='/etc/grml/fai'
364 [ -n "$GRML_NAME" ] || GRML_NAME='grml'
365 [ -n "$HOSTNAME" ] || HOSTNAME='grml'
366 [ -n "$HYBRID_METHOD" ] || HYBRID_METHOD='manifold'
367 [ -n "$NFSROOT_CONF" ] || NFSROOT_CONF="${GRML_FAI_CONFIG}/make-fai-nfsroot.conf"
368 [ -n "$RELEASENAME" ] || RELEASENAME='grml-live rocks'
369 [ -n "$SQUASHFS_EXCLUDES_FILE" ] || SQUASHFS_EXCLUDES_FILE="${GRML_FAI_CONFIG}/config/grml/squashfs-excludes"
370 [ -n "$SUITE" ] || SUITE='squeeze'
371 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
372 [ -n "$USERNAME" ] || USERNAME='grml'
373 [ -n "$VERSION" ] || VERSION='0.0.1'
375 # output specific stuff, depends on $OUTPUT (iff not set):
376 [ -n "$OUTPUT" ] || OUTPUT='/grml/grml-live'
377 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
378 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
379 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
380 [ -n "$LOG_OUTPUT" ] || LOG_OUTPUT="$OUTPUT/grml_logs"
381 [ -n "$REPORTS" ] || REPORTS="${LOG_OUTPUT}/reports/"
382 [ -n "$NETBOOT" ] || NETBOOT="${OUTPUT}/netboot/"
385 # some misc checks before executing FAI {{{
386 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
387 specify it on the command line using the -c option."
388 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
389 specify it on the command line using the -o option."
391 # trim characters that are known to cause problems inside $GRML_NAME;
392 # for example isolinux does not like '-' inside the directory name
393 [ -n "$GRML_NAME" ] && export SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
395 # export variables to have them available in fai scripts:
396 [ -n "$GRML_NAME" ] && export GRML_NAME="$GRML_NAME"
397 [ -n "$RELEASENAME" ] && export RELEASENAME="$RELEASENAME"
400 # ZERO_LOGFILE - check for backwards compatibility reasons {{{
401 # this was default behaviour until grml-live 0.9.34:
402 if [ -n "$ZERO_LOGFILE" ] ; then
403 PRESERVE_LOGFILE='' # make sure it's cleaned then
404 ewarn "Please consider disabling the \$ZERO_LOGFILE option as grml-live clears..."
405 ewarn "... the logfile $LOGFILE by default (unless \$PRESERVE_LOGFILE is set) nowadays."
410 # ask user whether the setup is ok {{{
411 if [ -z "$FORCE" ] ; then
413 echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
415 echo " FAI classes: $CLASSES"
416 [ -n "$LOCAL_CONFIG" ] && echo " Configuration: $LOCAL_CONFIG"
417 [ -n "$GRML_FAI_CONFIG" ] && echo " Config directory: $GRML_FAI_CONFIG"
418 echo " main directory: $OUTPUT"
419 [ -n "$EXTRACT_ISO_NAME" ] && echo " Extract ISO: $EXTRACT_ISO_NAME"
420 [ -n "$CHROOT_OUTPUT" ] && echo " Chroot target: $CHROOT_OUTPUT"
421 [ -n "$BUILD_OUTPUT" ] && echo " Build target: $BUILD_OUTPUT"
422 [ -n "$ISO_OUTPUT" ] && echo " ISO target: $ISO_OUTPUT"
423 [ -n "$GRML_NAME" ] && echo " Grml name: $GRML_NAME"
424 [ -n "$RELEASENAME" ] && echo " Release name: $RELEASENAME"
425 [ -n "$DATE" ] && echo " Build date: $DATE"
426 [ -n "$VERSION" ] && echo " Grml version: $VERSION"
427 [ -n "$SUITE" ] && echo " Debian suite: $SUITE"
428 [ -n "$ARCH" ] && echo " Architecture: $ARCH"
429 [ -n "$BOOT_METHOD" ] && echo " Boot method: $BOOT_METHOD"
430 [ -n "$HYBRID_METHOD" ] && echo " Hybrid method: $HYBRID_METHOD"
431 [ -n "$TEMPLATE_DIRECTORY" ] && echo " Template files: $TEMPLATE_DIRECTORY"
432 [ -n "$CHROOT_INSTALL" ] && echo " Install files from directory to chroot: $CHROOT_INSTALL"
433 [ -n "$BOOTID" ] && echo " Boot identifier: $BOOTID"
434 [ -n "$NO_BOOTID" ] && echo " Skipping bootid feature."
435 [ -n "$CHOWN_USER" ] && echo " Output owner: $CHOWN_USER"
436 [ -n "$DEFAULT_BOOTOPTIONS" ] && echo " Adding default bootoptions: \"$DEFAULT_BOOTOPTIONS\""
437 [ -n "$FAI_ARGS" ] && echo " Additional arguments for FAI: $FAI_ARGS"
438 [ -n "$LOGFILE" ] && echo " Logging to file: $LOGFILE"
439 [ -n "$SQUASHFS_ZLIB" ] && echo " Using ZLIB (instead of LZMA/XZ) compression."
440 [ -n "$SQUASHFS_OPTIONS" ] && echo " Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
441 [ -n "$VERBOSE" ] && echo " Using VERBOSE mode."
442 [ -n "$CLEAN_ARTIFACTS" ] && echo " Will clean output before and after running."
443 [ -n "$UPDATE" ] && echo " Executing UPDATE instead of fresh installation."
444 if [ -n "$BOOTSTRAP_ONLY" ] ; then
445 echo " Bootstrapping only and not building (files for) ISO."
447 [ -n "$SKIP_MKSQUASHFS" ] && echo " Skipping creation of SQUASHFS file."
448 [ -n "$SKIP_NETBOOT" ] && echo " Skipping creation of NETBOOT package."
449 [ -n "$SKIP_MKISOFS" ] && echo " Skipping creation of ISO file."
450 [ -n "$BUILD_ONLY" ] && echo " Executing BUILD_ONLY instead of fresh installation or UPDATE."
451 [ -n "$BUILD_DIRTY" ] && echo " Executing BUILD_DIRTY to leave chroot untouched."
454 echo -n "Is this ok for you? [y/N] "
456 if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
457 bailout 1 "Exiting as requested."
463 # clean up before start {{{
464 if [ -n "${CLEAN_ARTIFACTS}" ]; then
465 echo "Wiping old artifacts"
466 [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && rm -r "${CHROOT_OUTPUT}"
467 [ -n "${BUILD_OUTPUT}" -a -d "${BUILD_OUTPUT}" ] && rm -r "${BUILD_OUTPUT}"
468 [ -n "${ISO_OUTPUT}" -a -d "${ISO_OUTPUT}" ] && rm -r "${ISO_OUTPUT}"
469 [ -n "${LOG_OUTPUT}" -a -d "${LOG_OUTPUT}" ] && rm -r "${LOG_OUTPUT}"
470 [ -n "${NETBOOT}" -a -d "${NETBOOT}" ] && rm -r "${NETBOOT}"
474 # create log file {{{
475 [ -n "$LOGFILE" ] || LOGFILE=${LOG_OUTPUT}/grml-live.log
476 mkdir -p $(dirname "${LOGFILE}")
478 chown root:adm $LOGFILE
482 # clean/zero/remove logfiles {{{
484 if [ -n "$PRESERVE_LOGFILE" ] ; then
485 echo "Preserving logfile $LOGFILE as requested via \$PRESERVE_LOGFILE"
487 # make sure it is empty (as it is e.g. appended to grml-live-db)
491 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
492 if [ -d /var/log/fai/"$HOSTNAME" ] ; then
493 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
494 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
495 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
496 rm -f /var/log/fai/"$HOSTNAME"/last \
497 /var/log/fai/"$HOSTNAME"/last-dirinstall \
498 /var/log/fai/"$HOSTNAME"/last-softupdate
503 # source config and startup {{{
504 if [ -n "$CONFIG" ] ; then
505 if ! [ -f "$CONFIG" ] ; then
506 log "Error: $CONFIG could not be read. Exiting. [$(date)]"
507 eerror "Error: $CONFIG could not be read. Exiting." ; eend 1
510 log "Sourcing $CONFIG"
515 start_seconds=$(cut -d . -f 1 /proc/uptime)
516 log "------------------------------------------------------------------------------"
517 log "Starting grml-live [${GRML_LIVE_VERSION}] run on $(date)"
518 log "Using local config file: $LOCAL_CONFIG"
519 log "Executed grml-live command line:"
522 einfo "Logging actions to logfile $LOGFILE"
525 # dump config variables into file, for script access {{{
528 '^(GRML_NAME|RELEASENAME|DATE|VERSION|SUITE|ARCH|DISTRI_NAME|USERNAME|HOSTNAME|APT_PROXY)=' \
532 # unpack iso/squashfs {{{
534 if [ -n "$EXTRACT_ISO_NAME" ]; then
535 log "Unpacking ISO from ${EXTRACT_ISO_NAME}"
536 einfo "Unpacking ISO from ${EXTRACT_ISO_NAME}"
537 local mountpoint=$(mktemp -d)
539 mount -o loop "${EXTRACT_ISO_NAME}" "$mountpoint" ; rc=$?
540 if [ "$rc" != 0 ]; then
543 eerror "mount failed"
547 unsquashfs -d "${CHROOT_OUTPUT}" "${mountpoint}"/live/*/*.squashfs ; rc=$?
550 if [ "$rc" != 0 ]; then
551 log "unsquashfs failed"
552 eerror "unsquashfs failed"
561 # on-the-fly configuration {{{
562 if [ -n "$FAI_DEBOOTSTRAP" ] ; then
563 sed "s#^FAI_DEBOOTSTRAP=.*#FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"#" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
566 # does this suck? YES!
567 # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
569 unstable) SUITE='sid' ; CLASSES="DEBIAN_UNSTABLE,$CLASSES" ;;
570 *) CLASSES="DEBIAN_$(echo $SUITE | tr 'a-z' 'A-Z'),$CLASSES";;
572 export SUITE # make sure it's available in FAI scripts
574 for file in "$LIVE_CONF" "$LOCAL_CONFIG" "$NFSROOT_CONF" ; do
575 if [ -n "$file" ] ; then
576 sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
580 # validate whether the specified architecture class matches the
581 # architecture (option), otherwise installation of kernel will fail
582 if echo $CLASSES | grep -qi i386 ; then
583 if ! [[ "$ARCH" == "i386" ]] ; then
584 log "Error: You specified the I386 class but are trying to build something else (AMD64?)."
585 eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
586 eerror "Tip: Either invoke grml-live with '-a i386' or adjust the architecture class. Exiting."
590 elif echo $CLASSES | grep -qi amd64 ; then
591 if ! [[ "$ARCH" == "amd64" ]] ; then
592 log "Error: You specified the AMD64 class but are trying to build something else (I386?)."
593 eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
594 eerror "Tip: Either invoke grml-live with '-a amd64' or adjust the architecture class. Exiting."
600 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
601 sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
603 sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
607 # CHROOT_OUTPUT - execute FAI {{{
608 if [ -n "$BUILD_DIRTY" ]; then
609 log "Skipping stage 'fai' as requested via option -B"
610 ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
612 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
614 # provide inform fai about the ISO we build
615 [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
616 echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
617 [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
618 [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
620 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
621 FAI_ACTION=softupdate
623 FAI_ACTION=dirinstall
626 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
627 if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
628 log "Error: does not look like you have a working chroot. Updating/building not possible."
629 eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
635 if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
636 log "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
637 ewarn "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
639 mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
641 if [ -n "${MIRROR_DIRECTORY}" ] ; then
642 mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
643 mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
646 mkdir -p "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
647 mount --bind "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
649 # tell dpkg to use "unsafe io" during the build
650 [ -d "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d" ] || mkdir -p "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d"
651 echo force-unsafe-io > "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
653 log "Executed FAI command line:"
654 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"
655 BUILD_ONLY="$BUILD_ONLY" BOOTSTRAP_ONLY="$BOOTSTRAP_ONLY" GRML_LIVE_CONFIG="$CONFIGDUMP" fai $VERBOSE \
656 -C "$GRML_FAI_CONFIG" -s "file:///$GRML_FAI_CONFIG/config" -c"$CLASSES" \
657 -u "$HOSTNAME" "$FAI_ACTION" "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
658 RC="$PIPESTATUS" # notice: bash-only
660 rm -f "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
662 FORCE_ISO_REBUILD=true
664 if [ "$RC" != 0 ] ; then
665 log "Error: critical error while executing fai [exit code ${RC}]. Exiting."
666 eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
670 # move fai logs into grml_logs directory
671 mkdir -p "$LOG_OUTPUT"/fai/
672 cp -r "$CHROOT_OUTPUT"/var/log/fai/"$HOSTNAME"/last/* "$LOG_OUTPUT"/fai/
673 rm -rf "$CHROOT_OUTPUT"/var/log/fai
674 # copy fai package list
675 cp "$CHROOT_OUTPUT"/var/log/install_packages.list "$LOG_OUTPUT"/fai/
677 chown root:adm "$LOG_OUTPUT"/fai/*
678 chmod 664 "$LOG_OUTPUT"/fai/*
682 # notice: 'fai dirinstall' does not seem to exit appropriate, so:
684 CHECKLOG="$LOG_OUTPUT"/fai/
685 if [ -r "$CHECKLOG/software.log" ] ; then
686 # 1 errors during executing of commands
687 grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
688 grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
689 grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
690 grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
691 grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
694 if [ -r "$CHECKLOG/shell.log" ] ; then
695 grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=6
698 if [ -n "$ERROR" ] ; then
699 log "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
700 eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
701 eerror "Note: check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
705 log "Finished execution of stage 'fai dirinstall' [$(date)]"
706 einfo "Finished execution of stage 'fai dirinstall'"
712 # package validator {{{
713 CHECKLOG=/var/log/fai/$HOSTNAME/last
714 if [ -r "$CHECKLOG/dpkg.selections" ] ; then
715 package_count=$(wc -l "$CHECKLOG/dpkg.selections" | awk '{print $1}')
717 package_count="unknown"
721 REPORT_MISSING_PACKAGES="${REPORTS}/TEST-MissingPackages.xml"
723 # check for missing packages
724 if ! [ -s "$CHECKLOG/package_errors.log" ] ; then
725 einfo "No missing packages found, generating empty junit report."
727 cat > "${REPORT_MISSING_PACKAGES}" << EOF
728 <?xml version="1.0" encoding="UTF-8"?>
729 <testsuite name="grml-live-missing-packages" tests="${package_count}" time="1" failures="0" errors="0" skipped="0" assertions="0">
730 <testcase name="test_missing_packages" time="0" assertions="0">
740 einfo "Missing packages found, generating junit report."
742 if [ -r "$CHECKLOG/package_errors.log" ] ; then
743 package_errors=$(wc -l "$CHECKLOG/package_errors.log" | awk '{print $1}')
745 package_errors="unknown"
749 REPORT_MISSING_PACKAGES="${REPORTS}/TEST-MissingPackages.xml"
751 cat > "${REPORT_MISSING_PACKAGES}" << EOF
752 <?xml version="1.0" encoding="UTF-8"?>
753 <testsuite name="grml-live-missing-packages" tests="${package_count}" time="1" failures="${package_errors}" errors="${package_errors}" skipped="0" assertions="0">
756 for package in $(awk '{print $5}' "${CHECKLOG}/package_errors.log" | sed 's/\.$//') ; do
757 cat >> "${REPORT_MISSING_PACKAGES}" << EOF
758 <testcase name="test_missing_packages_${package}" time="0" assertions="0">
759 <failure type="RuntimeError" message="Package ${package} is missing">
760 Package $package is missing in chroot
766 cat >> "${REPORT_MISSING_PACKAGES}" << EOF
775 if [ -n "$EXIT_ON_MISSING_PACKAGES" -a -z "$BUILD_DIRTY" ] ; then
776 eerror "The following packages were requested for installation but could not be processed:"
777 cat "$CHECKLOG/package_errors.log"
778 eerror "... exiting as requested via \$EXIT_ON_MISSING_PACKAGES."
782 ewarn "The following packages were requested for installation but could not be processed:"
783 cat "$CHECKLOG/package_errors.log"
789 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
790 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
791 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
794 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
795 if [ -n "$BOOTSTRAP_ONLY" ] ; then
796 log "Skipping stage 'boot' as building with bootstrap only."
797 ewarn "Skipping stage 'boot' as building with bootstrap only." ; eend 0
799 if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
800 log "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already."
801 ewarn "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already." ; eend 0
804 [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
805 [ -d "$BUILD_OUTPUT"/boot/"${SHORT_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
807 # if we don't have an initrd we a) can't boot and b) there was an error
808 # during build, so check for the file:
809 INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
810 if [ -n "$INITRD" ] ; then
811 cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.img
812 find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
814 log "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
815 eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
819 KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
820 if [ -n "$KERNEL_IMAGE" ] ; then
821 cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/vmlinuz
823 log "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
824 eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
829 if [ -r "${CHROOT_OUTPUT}/boot/efi.img" -a -r "${CHROOT_OUTPUT}/boot/bootx64.efi" ] ; then
830 einfo "Moving EFI boot files into ISO path."
831 log "Moving EFI boot files into ISO path."
833 mv "${CHROOT_OUTPUT}/boot/efi.img" "${BUILD_OUTPUT}/boot/" || RC=$?
834 mkdir -p "${BUILD_OUTPUT}/efi/boot/" || RC=$?
835 mv "${CHROOT_OUTPUT}/boot/bootx64.efi" "${BUILD_OUTPUT}/efi/boot/bootx64.efi" || RC=$?
839 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
840 if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
841 log "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
842 eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
846 # copy _required_ isolinux files
847 for file in ifcpu64.c32 isolinux.bin vesamenu.c32; do
848 copy_addon_file "${file}" /usr/lib/syslinux isolinux
851 # *always* copy files to output directory so the variables
852 # get adjusted according to the build.
853 cp ${TEMPLATE_DIRECTORY}/boot/isolinux/* "$BUILD_OUTPUT"/boot/isolinux/
855 if [ -n "$NO_ADDONS" ] ; then
856 log "Skipping installation of boot addons as requested via \$NO_ADDONS."
857 einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
859 if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
860 log "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
861 ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
863 # copy addons from system packages or grml-live-compat
864 copy_addon_file ipxe.lkrn /usr/lib/ipxe addons
865 copy_addon_file pci.ids /usr/share/misc addons
866 copy_addon_file memtest86+.bin /boot addons
867 for file in memdisk chain.c32 hdt.c32 menu.c32; do
868 copy_addon_file "${file}" /usr/lib/syslinux addons
871 # make memtest filename FAT16/8.3 compatible
872 mv "${BUILD_OUTPUT}/boot/addons/memtest86+.bin" \
873 "${BUILD_OUTPUT}/boot/addons/memtest"
875 # copy only files so we can handle bsd4grml on its own
876 for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
877 test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
880 if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
881 log "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
882 einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
884 if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
885 cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
887 log "Missing addon file: bsd4grml"
888 ewarn "Missing addon file: bsd4grml" ; eend 0
892 fi # no "$TEMPLATE_DIRECTORY"/boot/addons
895 if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
896 mkdir -p "${BUILD_OUTPUT}/boot/grub"
898 cp -a ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
900 # copy grub files from target
901 cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/*-pc/*.mod "${BUILD_OUTPUT}"/boot/grub/
902 cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/*-pc/*.o "${BUILD_OUTPUT}"/boot/grub/
903 cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/*-pc/*.lst "${BUILD_OUTPUT}"/boot/grub/
904 cp -a "${CHROOT_OUTPUT}"/usr/share/grub/ascii.pf2 "${BUILD_OUTPUT}"/boot/grub/
905 cp -a "${CHROOT_OUTPUT}"/boot/grub/core.img "${BUILD_OUTPUT}"/boot/grub/
906 cp -a "${CHROOT_OUTPUT}"/boot/grub/grub.img "${BUILD_OUTPUT}"/boot/grub/
908 if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
909 log "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
910 eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
914 mkdir -p "$BUILD_OUTPUT"/GRML/"${GRML_NAME}"/
915 cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/"${GRML_NAME}"/
917 # adjust boot splash information:
918 RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
919 RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
920 RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
922 if [ -r "$BUILD_OUTPUT"/GRML/"${GRML_NAME}"/grml-version ] ; then
923 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/"${GRML_NAME}"/grml-version
924 sed -i "s/%DATE%/$DATE/" "$BUILD_OUTPUT"/GRML/"${GRML_NAME}"/grml-version
927 # make sure the squashfs filename is set accordingly:
928 SQUASHFS_NAME="$GRML_NAME.squashfs"
930 if [ -n "$NO_BOOTID" ] ; then
931 log 'Skipping bootid feature as requested via $NO_BOOTID.'
932 einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
934 [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
935 [ -d "$BUILD_OUTPUT"/conf ] || mkdir "$BUILD_OUTPUT"/conf
936 einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
937 log "Generating /conf/bootid.txt with entry ${BOOTID}."
938 echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
942 # adjust all variables in the templates with the according distribution information
943 for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
944 "${BUILD_OUTPUT}"/boot/grub/* ; do
945 if [ -r "${file}" ] && [ -f "${file}" ] ; then
946 sed -i "s/%ARCH%/$ARCH/g" "${file}"
947 sed -i "s/%DATE%/$DATE/g" "${file}"
948 sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g" "${file}"
949 sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g" "${file}"
950 sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g" "${file}"
951 sed -i "s/%GRML_NAME%/$GRML_NAME/g" "${file}"
952 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g" "${file}"
953 sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g" "${file}"
954 sed -i "s/%SHORT_NAME%/$SHORT_NAME/g" "${file}"
955 sed -i "s/%VERSION%/$VERSION/g" "${file}"
957 [ -n "$DEFAULT_BOOTOPTIONS" ] && sed -i "s/ boot=live/ boot=live $DEFAULT_BOOTOPTIONS/" "${file}"
959 if [ -n "$NO_BOOTID" ] ; then
960 sed -i "s/ bootid=%BOOTID%//g" "${file}" # drop bootid bootoption
962 sed -i "s/%BOOTID%/$BOOTID/g" "${file}" # adjust bootid=... argument
967 for param in ARCH DATE DISTRI_INFO DISTRI_NAME DISTRI_SPLASH GRML_NAME SQUASHFS_NAME \
968 RELEASE_INFO SHORT_NAME VERSION ; do
969 for file in $(find "${BUILD_OUTPUT}" -name "*%$param%*") ; do
970 value="$(eval echo '$'"$param")"
971 mv ${file} ${file/\%${param}\%/$value}
975 # adjust bootsplash accordingly but make sure the string has the according lenght
976 SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
977 SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
978 for file in f4 f5 ; do
979 if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
980 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
981 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
985 # generate addon list
986 rm -f "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
987 for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
988 include_name=$(basename "$name")
989 echo "include $include_name" >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
992 if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
993 log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
994 echo "include grmlmain.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
995 echo "include default.cfg" > "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
996 echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
997 echo "include grml.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
999 for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
1000 echo "include $(basename $f)" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1003 echo "include options.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1004 if [ ! -n "$NO_ADDONS" ] ; then
1005 echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1007 echo "include isoprompt.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1008 echo "include hd.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1009 echo "include hidden.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1010 else # assume we are building a custom distribution:
1011 log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
1012 einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
1013 if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
1014 log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
1016 einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
1020 log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1021 echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1022 [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1026 # use old style console based isolinux method only if requested:
1027 if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
1028 log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
1029 einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
1030 if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
1031 einfo "include for console.cfg already found, nothing to do."
1034 log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1035 einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1036 echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1040 log 'Using graphical boot menu.'
1041 if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
1042 log "include for vesamenu.cfg already found, nothing to do."
1044 log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1045 echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1049 if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
1050 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
1053 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
1054 if ! [ -r "$DPKG_LIST" ] ; then
1055 ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
1057 einfo "Storing package list information as /GRML/${GRML_NAME}/packages.txt on ISO."
1058 cp "$DPKG_LIST" "${BUILD_OUTPUT}"/GRML/"${GRML_NAME}"/packages.txt
1062 # autostart for Windows:
1063 if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
1064 cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
1067 FORCE_ISO_REBUILD=true
1068 einfo "Finished execution of stage 'boot'" ; eend 0
1072 log 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
1073 eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
1077 # support installation of local files into the chroot/ISO
1078 if [ -n "$CHROOT_INSTALL" ] ; then
1079 if ! [ -d "$CHROOT_INSTALL" ] ; then
1080 log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1081 ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1083 log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1084 einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1085 rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
1087 einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
1088 FORCE_ISO_REBUILD=true
1092 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
1093 log "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
1094 ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
1095 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
1096 log "Skipping stage 'squashfs' as requested via option -q or -N"
1097 ewarn "Skipping stage 'squashfs' as requested via option -q or -N" ; eend 0
1099 mkdir -p "$BUILD_OUTPUT"/live/"${GRML_NAME}"/
1100 # make sure we don't leave (even an empty) base.tgz:
1101 [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
1103 # if unconfigured default to squashfs-tools' mksquashfs binary
1104 if [ -z "$SQUASHFS_BINARY" ] ; then
1105 SQUASHFS_BINARY='mksquashfs'
1108 if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
1109 log "Using mksquashfs binary ${SQUASHFS_BINARY}"
1110 einfo "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
1112 log "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
1113 eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
1117 # use sane defaults if $SQUASHFS_OPTIONS isn't set
1118 if [ -z "$SQUASHFS_OPTIONS" ] ; then
1119 # use blocksize 256k as this gives best result with regards to time + compression
1120 SQUASHFS_OPTIONS="-b 256k"
1122 # set lzma/xz compression by default, unless -z option has been specified on command line
1123 if [ -z "$SQUASHFS_ZLIB" ] ; then
1124 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp xz"
1126 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp gzip"
1130 # support exclusion of files via exclude-file:
1131 if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
1132 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE -wildcards"
1135 # get rid of unnecessary files when building grml-small for final release:
1136 if echo "$CLASSES" | grep -q GRML_SMALL ; then
1137 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
1141 SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
1143 # informational stuff
1144 [ -n "$SQUASHFS_OPTIONS" ] && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
1145 [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
1146 einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
1148 log "$SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/${GRML_NAME}/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS"
1150 if $SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/"${GRML_NAME}"/"${GRML_NAME}".squashfs \
1151 -noappend $SQUASHFS_OPTIONS 2>"${SQUASHFS_STDERR}" ; then
1152 echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/"${GRML_NAME}"/filesystem.module
1153 log "Finished execution of stage 'squashfs' [$(date)]"
1154 einfo "Finished execution of stage 'squashfs'" ; eend 0
1156 log "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1157 log "$(cat $SQUASHFS_STDERR)"
1158 eerror "Error: there was a critical error executing stage 'squashfs':"
1159 cat "${SQUASHFS_STDERR}"
1164 FORCE_ISO_REBUILD=true
1167 # create md5sum file:
1168 if [ -z "$BOOTSTRAP_ONLY" ] ; then
1169 ( cd $BUILD_OUTPUT/GRML/"${GRML_NAME}" &&
1170 find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1174 # ISO_OUTPUT - mkisofs {{{
1175 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1176 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1178 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1179 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1180 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1181 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1184 # Just until http://bts.grml.org/grml/issue945 has been resolved.
1185 # HYBRID_METHOD defaults to manifold, so make sure the default works OOTB.
1186 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1187 log "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1188 ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1189 HYBRID_METHOD='grub2'
1193 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ] ; then
1194 log "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1195 ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1196 elif [ -n "$SKIP_MKISOFS" ] ; then
1197 log "Skipping stage 'iso build' as requested via option -n or -N"
1198 ewarn "Skipping stage 'iso build' as requested via option -n or -N" ; eend 0
1200 mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1202 if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1203 log "Forcing rebuild of ISO because files on ISO have been modified."
1204 einfo "Forcing rebuild of ISO because files on ISO have been modified."
1207 # support xorriso as well mkisofs and genisoimage
1208 if which xorriso >/dev/null 2>&1 ; then
1209 MKISOFS='xorriso -as mkisofs'
1210 elif which mkisofs >/dev/null 2>&1; then
1212 elif which genisoimage >/dev/null 2>&1; then
1213 MKISOFS='genisoimage'
1215 log "Error: neither xorriso nor mkisofs nor genisoimage available - can not create ISO."
1216 eerror "Error: neither xorriso nor mkisofs nor genisoimage available - can not create ISO." ; eend 1
1220 einfo "Using ${MKISOFS} to build ISO." ; eend 0
1221 case "${ARCH}-${MKISOFS}" in
1222 # using -eltorito-alt-boot is limited to xorriso for now
1226 if ! dpkg --compare-versions $(dpkg-query -W -f='${Version}\n' xorriso 2>/dev/null) gt-nl 1.1.6-1 ; then
1227 log "Disabling (U)EFI boot support because xorriso version is too old."
1228 ewarn "Disabling (U)EFI boot support because xorriso version is too old." ; eend 0
1230 if [ -r "${BUILD_OUTPUT}"/boot/efi.img ] ; then
1231 einfo "Enabling (U)EFI boot."
1232 log "Enabling (U)EFI boot."
1233 BOOT_ARGS="$BOOT_ARGS -boot-info-table -eltorito-alt-boot -e boot/efi.img -no-emul-boot"
1236 log "Disabling (U)EFI boot support because /boot/efi.img is missing."
1237 ewarn "Disabling (U)EFI boot support because /boot/efi.img is missing." ; eend 0
1246 if cd "$BUILD_OUTPUT" ; then
1247 if [ "$BOOT_METHOD" = "grub2" ]; then
1248 # make a 2048-byte bootsector for El Torito
1249 dd if=/dev/zero of=boot/grub/toriboot.bin bs=512 count=4 2>/dev/null
1250 # those are in 2048-byte sectors, so 1 16 matches 4 63 below
1251 echo 1 16 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -B 11 | \
1252 dd of=boot/grub/toriboot.bin conv=notrunc 2>/dev/null
1254 log "$MKISOFS -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J $BOOT_ARGS -o ${ISO_OUTPUT}/${ISO_NAME} ."
1255 $MKISOFS -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1256 -l -r -J $BOOT_ARGS -no-pad \
1257 -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1258 # both of these need core.img there, so it’s easier to write it here
1259 if [ "$BOOT_METHOD" = "grub2" ] || [ "$HYBRID_METHOD" = "grub2" ]; then
1260 # must be <= 30720 bytes
1261 dd if=boot/grub/core.img of="${ISO_OUTPUT}/${ISO_NAME}" \
1262 conv=notrunc bs=512 seek=4 2>/dev/null
1265 # pad the output ISO to multiples of 256 KiB for partition table support
1266 siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1267 cyls=$((siz / 512 / 32 / 16 + 1)) # C=$cyls H=16 S=32
1268 siz=$((cyls * 16 * 32 * 512)) # size after padding
1269 dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1270 of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1272 # support disabling hybrid ISO image
1273 if [ "$HYBRID_METHOD" = "disable" ] ; then\
1274 log "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1275 einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1277 elif [ "$HYBRID_METHOD" = "manifold" ] ; then
1278 # isoinfo is part of both mkisofs and genisoimage so we're good
1279 bootoff=$(isoinfo -l -i "${ISO_OUTPUT}/${ISO_NAME}" | \
1280 sed -n '/^.*\[ *\([0-9]*\)[] ].* ISOLINUX.BIN[;1]* *$/s//\1/p')
1281 if ! [ -r boot/grub/core.img ] ; then
1282 ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1283 elif [ "${bootoff:-0}" -lt 1 ] ; then
1284 ewarn "isolinux.bin not found on the ISO file, disabling manifold boot"
1286 log "Creating hybrid ISO file with manifold method"
1287 einfo "Creating hybrid ISO file with manifold method"
1288 if [ "$HYBRID_METHOD" = "grub2" ] ; then
1289 # 512 bytes: MBR, partition table, load GRUB 2
1290 echo 4 63 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 4:0x96 -g $cyls:16:32
1292 # read only one but 2048-byte sized (scale: << 2) sector
1293 echo $bootoff $bootoff | \
1294 mksh /usr/share/grml-live/scripts/bootilnx.mksh -A -M 4:0x96 -g $cyls:16:32 -S 2
1295 fi | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1298 # use isohybrid as default
1300 if ! which isohybrid >/dev/null 2>&1 ; then
1301 bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1303 log "Creating hybrid ISO file with isohybrid method"
1304 einfo "Creating hybrid ISO file with isohybrid method"
1305 # Notes for consideration:
1306 # "-entry 4 -type 1c"
1307 # * using 4 as the partition number is supposed to help with BIOSes
1308 # that only support USB-Zip boot
1309 # * using 1c (i.e. hidden FAT32 LBA), instead of the default 0x17
1310 # (hidden NTFS, IIRC), as the partition type is sometimes needed
1311 # to get the BIOS even look at the partition created by isohybrid
1312 if isohybrid --help | grep -q -- --uefi ; then
1313 einfo "Detected uefi support for isohybrid, enabling."
1314 ISOHYBRID_OPTIONS=--uefi
1317 log "isohybrid $ISOHYBRID_OPTIONS ${ISO_OUTPUT}/${ISO_NAME}"
1318 isohybrid $ISOHYBRID_OPTIONS "${ISO_OUTPUT}/${ISO_NAME}"
1323 # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1324 case $CLASSES in *RELEASE*)
1327 if cd $ISO_OUTPUT ; then
1328 md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1329 touch -r ${ISO_NAME} ${ISO_NAME}.md5
1330 sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1331 touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1340 if [ "$RC" = 0 ] ; then
1341 log "Finished execution of stage 'iso build' [$(date)]"
1342 einfo "Finished execution of stage 'iso build'" ; eend 0
1344 log "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1345 eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1351 # netboot package {{{
1352 create_netbootpackage() {
1353 local OUTPUT_FILE="${NETBOOT}/grml_netboot_package_${GRML_NAME}_${VERSION}.tar.bz2"
1355 if [ -f "${OUTPUT_FILE}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
1356 log "Skipping stage 'netboot' as $OUTPUT_FILE exists already."
1357 ewarn "Skipping stage 'netboot' as $OUTPUT_FILE exists already." ; eend 0
1359 elif [ -n "$SKIP_NETBOOT" ] ; then
1360 log "Skipping stage 'netboot' as requested via option -Q"
1361 ewarn "Skipping stage 'netboot' as requested via option -Q" ; eend 0
1367 if ! [ -r "${CHROOT}/usr/lib/syslinux/pxelinux.0" ] ; then
1368 ewarn "File /usr/lib/syslinux/pxelinux.0 not found in build chroot." ; eend 0
1370 einfo "Install syslinux[-common] package in chroot to get a netboot package."
1375 local OUTPUTDIR="${NETBOOT}/build_tmp"
1376 local WORKING_DIR="${OUTPUTDIR}/grml_netboot_package_${GRML_NAME}_${VERSION}/tftpboot/"
1378 mkdir -p "$WORKING_DIR"
1380 cp "${CHROOT_OUTPUT}"/boot/vmlinuz-* "$WORKING_DIR"/vmlinuz
1381 cp "${CHROOT_OUTPUT}"/boot/initrd.img-* "$WORKING_DIR"/initrd.img
1382 cp "${CHROOT_OUTPUT}"/usr/lib/syslinux/pxelinux.0 "${WORKING_DIR}/pxelinux.0"
1384 mkdir -p "${WORKING_DIR}/pxelinux.cfg"
1385 if [ -r "${BUILD_OUTPUT}/boot/isolinux/netboot.cfg" ] ; then
1386 cp "${BUILD_OUTPUT}/boot/isolinux/netboot.cfg" "${WORKING_DIR}/pxelinux.cfg/default"
1388 ewarn "File ${BUILD_OUTPUT}/boot/isolinux/netboot.cfg not found." ; eend 0
1391 if tar -C "$OUTPUTDIR" -jcf "${OUTPUT_FILE}" "grml_netboot_package_${GRML_NAME}_${VERSION}" ; then
1393 cd $(dirname "${OUTPUT_FILE}")
1394 sha1sum $(basename "${OUTPUT_FILE}") > "${OUTPUT_FILE}.sha1"
1396 einfo "Generated netboot package ${OUTPUT_FILE}" ; eend 0
1397 rm -rf "${OUTPUTDIR}"
1399 rm -rf "${OUTPUTDIR}"
1400 eerror "Could not generate netboot package ${OUTPUT_FILE}" ; eend 1
1405 create_netbootpackage
1408 # log build information to database if grml-live-db is installed and enabled {{{
1410 if [ -d /usr/share/grml-live-db ] ; then
1413 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1414 [ -n "$DPKG_DATABASE" ] || DPKG_DATABASE=/var/log/grml-live.db
1415 [ -n "$DPKG_DBSCRIPT" ] || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1416 [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1418 if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1419 log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1420 eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1424 # disable by default for now, not sure whether really everyone is using a local db file
1425 #if ! touch "$DPKG_DATABASE" ; then
1426 # eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1430 if ! [ -r "$DPKG_LIST" ] ; then
1431 log "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1432 ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1434 einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1435 log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1436 log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1439 if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1455 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1456 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1458 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1460 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1464 ## END OF FILE #################################################################
1465 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2