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
827 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
828 if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
829 log "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
830 eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
834 # copy _required_ isolinux files
835 for file in ifcpu64.c32 isolinux.bin vesamenu.c32; do
836 copy_addon_file "${file}" /usr/lib/syslinux isolinux
839 # *always* copy files to output directory so the variables
840 # get adjusted according to the build.
841 cp ${TEMPLATE_DIRECTORY}/boot/isolinux/* "$BUILD_OUTPUT"/boot/isolinux/
843 if [ -n "$NO_ADDONS" ] ; then
844 log "Skipping installation of boot addons as requested via \$NO_ADDONS."
845 einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
847 if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
848 log "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
849 ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
851 # copy addons from system packages or grml-live-compat
852 copy_addon_file ipxe.lkrn /usr/lib/ipxe addons
853 copy_addon_file pci.ids /usr/share/misc addons
854 copy_addon_file memtest86+.bin /boot addons
855 for file in memdisk chain.c32 hdt.c32 menu.c32; do
856 copy_addon_file "${file}" /usr/lib/syslinux addons
859 # make memtest filename FAT16/8.3 compatible
860 mv "${BUILD_OUTPUT}/boot/addons/memtest86+.bin" \
861 "${BUILD_OUTPUT}/boot/addons/memtest"
863 # copy only files so we can handle bsd4grml on its own
864 for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
865 test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
868 if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
869 log "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
870 einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
872 if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
873 cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
875 log "Missing addon file: bsd4grml"
876 ewarn "Missing addon file: bsd4grml" ; eend 0
880 fi # no "$TEMPLATE_DIRECTORY"/boot/addons
883 if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
884 mkdir -p "${BUILD_OUTPUT}/boot/grub"
886 cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
888 # copy grub files from target
889 cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/*-pc/*.mod "${BUILD_OUTPUT}"/boot/grub/
890 cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/*-pc/*.o "${BUILD_OUTPUT}"/boot/grub/
891 cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/*-pc/*.lst "${BUILD_OUTPUT}"/boot/grub/
892 cp -a "${CHROOT_OUTPUT}"/usr/share/grub/ascii.pf2 "${BUILD_OUTPUT}"/boot/grub/
893 cp -a "${CHROOT_OUTPUT}"/boot/grub/core.img "${BUILD_OUTPUT}"/boot/grub/
895 if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
896 log "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
897 eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
901 [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
902 cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
904 # adjust boot splash information:
905 RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
906 RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
907 RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
909 if [ -r "$BUILD_OUTPUT"/GRML/grml-version ] ; then
910 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
911 sed -i "s/%DATE%/$DATE/" "$BUILD_OUTPUT"/GRML/grml-version
914 # make sure the squashfs filename is set accordingly:
915 SQUASHFS_NAME="$GRML_NAME.squashfs"
917 if [ -n "$NO_BOOTID" ] ; then
918 log 'Skipping bootid feature as requested via $NO_BOOTID.'
919 einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
921 [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
922 [ -d "$BUILD_OUTPUT"/conf ] || mkdir "$BUILD_OUTPUT"/conf
923 einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
924 log "Generating /conf/bootid.txt with entry ${BOOTID}."
925 echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
929 # adjust all variables in the templates with the according distribution information
930 for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
931 "${BUILD_OUTPUT}"/boot/grub/* ; do
932 if [ -r "${file}" ] ; then
933 sed -i "s/%ARCH%/$ARCH/g" "${file}"
934 sed -i "s/%DATE%/$DATE/g" "${file}"
935 sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g" "${file}"
936 sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g" "${file}"
937 sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g" "${file}"
938 sed -i "s/%GRML_NAME%/$GRML_NAME/g" "${file}"
939 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g" "${file}"
940 sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g" "${file}"
941 sed -i "s/%SHORT_NAME%/$SHORT_NAME/g" "${file}"
942 sed -i "s/%VERSION%/$VERSION/g" "${file}"
944 [ -n "$DEFAULT_BOOTOPTIONS" ] && sed -i "s/ boot=live/ boot=live $DEFAULT_BOOTOPTIONS/" "${file}"
946 if [ -n "$NO_BOOTID" ] ; then
947 sed -i "s/ bootid=%BOOTID%//g" "${file}" # drop bootid bootoption
949 sed -i "s/%BOOTID%/$BOOTID/g" "${file}" # adjust bootid=... argument
954 for param in ARCH DATE DISTRI_INFO DISTRI_NAME DISTRI_SPLASH GRML_NAME SQUASHFS_NAME \
955 RELEASE_INFO SHORT_NAME VERSION ; do
956 for file in $(find "${BUILD_OUTPUT}" -name "*%$param%*") ; do
957 value="$(eval echo '$'"$param")"
958 mv ${file} ${file/\%${param}\%/$value}
962 # adjust bootsplash accordingly but make sure the string has the according lenght
963 SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
964 SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
965 for file in f4 f5 ; do
966 if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
967 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
968 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
972 # generate addon list
973 rm -f "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
974 for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
975 include_name=$(basename "$name")
976 echo "include $include_name" >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
979 if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
980 log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
981 echo "include grmlmain.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
982 echo "include default.cfg" > "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
983 echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
984 echo "include grml.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
986 for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
987 echo "include $(basename $f)" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
990 echo "include options.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
991 if [ ! -n "$NO_ADDONS" ] ; then
992 echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
994 echo "include isoprompt.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
995 echo "include hd.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
996 echo "include hidden.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
997 else # assume we are building a custom distribution:
998 log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
999 einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
1000 if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
1001 log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
1003 einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
1007 log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1008 echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1009 [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1013 # use old style console based isolinux method only if requested:
1014 if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
1015 log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
1016 einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
1017 if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
1018 einfo "include for console.cfg already found, nothing to do."
1021 log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1022 einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1023 echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1027 log 'Using graphical boot menu.'
1028 if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
1029 log "include for vesamenu.cfg already found, nothing to do."
1031 log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1032 echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1036 if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
1037 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
1040 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
1041 if ! [ -r "$DPKG_LIST" ] ; then
1042 ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
1044 einfo "Storing package list information as /GRML/${GRML_NAME}-packages.txt on ISO."
1045 cp "$DPKG_LIST" "${BUILD_OUTPUT}/GRML/${GRML_NAME}-packages.txt"
1049 # autostart for Windows:
1050 if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
1051 cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
1054 FORCE_ISO_REBUILD=true
1055 einfo "Finished execution of stage 'boot'" ; eend 0
1059 log 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
1060 eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
1064 # support installation of local files into the chroot/ISO
1065 if [ -n "$CHROOT_INSTALL" ] ; then
1066 if ! [ -d "$CHROOT_INSTALL" ] ; then
1067 log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1068 ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1070 log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1071 einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1072 rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
1074 einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
1075 FORCE_ISO_REBUILD=true
1079 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
1080 log "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
1081 ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
1082 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
1083 log "Skipping stage 'squashfs' as requested via option -q or -N"
1084 ewarn "Skipping stage 'squashfs' as requested via option -q or -N" ; eend 0
1086 [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
1087 # make sure we don't leave (even an empty) base.tgz:
1088 [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
1090 # if unconfigured default to squashfs-tools' mksquashfs binary
1091 if [ -z "$SQUASHFS_BINARY" ] ; then
1092 SQUASHFS_BINARY='mksquashfs'
1095 if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
1096 log "Using mksquashfs binary ${SQUASHFS_BINARY}"
1097 einfo "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
1099 log "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
1100 eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
1104 # use sane defaults if $SQUASHFS_OPTIONS isn't set
1105 if [ -z "$SQUASHFS_OPTIONS" ] ; then
1106 # use blocksize 256k as this gives best result with regards to time + compression
1107 SQUASHFS_OPTIONS="-b 256k"
1109 # set lzma/xz compression by default, unless -z option has been specified on command line
1110 if [ -z "$SQUASHFS_ZLIB" ] ; then
1111 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp xz"
1113 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp gzip"
1117 # support exclusion of files via exclude-file:
1118 if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
1119 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE -wildcards"
1122 # get rid of unnecessary files when building grml-small for final release:
1123 if echo "$CLASSES" | grep -q GRML_SMALL ; then
1124 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
1128 SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
1130 # informational stuff
1131 [ -n "$SQUASHFS_OPTIONS" ] && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
1132 [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
1133 einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
1135 log "$SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS"
1137 if $SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
1138 -noappend $SQUASHFS_OPTIONS 2>"${SQUASHFS_STDERR}" ; then
1139 echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
1140 log "Finished execution of stage 'squashfs' [$(date)]"
1141 einfo "Finished execution of stage 'squashfs'" ; eend 0
1143 log "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1144 log "$(cat $SQUASHFS_STDERR)"
1145 eerror "Error: there was a critical error executing stage 'squashfs':"
1146 cat "${SQUASHFS_STDERR}"
1151 FORCE_ISO_REBUILD=true
1154 # create md5sum file:
1155 if [ -z "$BOOTSTRAP_ONLY" ] ; then
1156 ( cd $BUILD_OUTPUT/GRML &&
1157 find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1161 # ISO_OUTPUT - mkisofs {{{
1162 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1163 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1165 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1166 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1167 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1168 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1171 # Just until http://bts.grml.org/grml/issue945 has been resolved.
1172 # HYBRID_METHOD defaults to manifold, so make sure the default works OOTB.
1173 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1174 log "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1175 ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1176 HYBRID_METHOD='grub2'
1180 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ] ; then
1181 log "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1182 ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1183 elif [ -n "$SKIP_MKISOFS" ] ; then
1184 log "Skipping stage 'iso build' as requested via option -n or -N"
1185 ewarn "Skipping stage 'iso build' as requested via option -n or -N" ; eend 0
1187 mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1189 if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1190 log "Forcing rebuild of ISO because files on ISO have been modified."
1191 einfo "Forcing rebuild of ISO because files on ISO have been modified."
1194 # support xorriso as well mkisofs and genisoimage
1195 if which xorriso >/dev/null 2>&1 ; then
1196 MKISOFS='xorriso -as mkisofs'
1197 elif which mkisofs >/dev/null 2>&1; then
1199 elif which genisoimage >/dev/null 2>&1; then
1200 MKISOFS='genisoimage'
1202 log "Error: neither xorriso nor mkisofs nor genisoimage available - can not create ISO."
1203 eerror "Error: neither xorriso nor mkisofs nor genisoimage available - can not create ISO." ; eend 1
1209 # using -eltorito-alt-boot is limited to xorriso for now
1212 einfo "Using xorriso for ISO generation." ; eend 0
1215 if ! dpkg --compare-versions $(dpkg-query -W -f='${Version}\n' xorriso 2>/dev/null) gt-nl 1.1.6-1 ; then
1216 log "Disabling (U)EFI boot support since xorriso version is not recent enough."
1217 ewarn "Disabling (U)EFI boot support since xorriso version is not recent enough." ; eend 0
1219 log "xorriso with -eltorito-alt-boot present, enabling (U)EFI boot support."
1220 einfo "xorriso with -eltorito-alt-boot present, enabling (U)EFI boot support." ; eend 0
1222 if [ -r "${CHROOT_OUTPUT}/var/lib/grml_live_efi.img" ] ; then
1223 einfo "Found /var/lib/grml_live_efi.img - moving to /boot/efi.img for ISO."
1224 log "Found /var/lib/grml_live_efi.img - moving to /boot/efi.img for ISO."
1225 mv "${CHROOT_OUTPUT}/var/lib/grml_live_efi.img" "${BUILD_OUTPUT}/boot/efi.img"
1229 if [ -r "${CHROOT_OUTPUT}/var/lib/grml_live_bootx64.efi" ] ; then
1230 einfo "Found /var/lib/grml_live_bootx64.efi - moving to /efi/boot/bootx64.efi for ISO"
1231 log "Found /var/lib/grml_live_bootx64.efi - moving to /efi/boot/bootx64.efi for ISO"
1232 mkdir -p "${BUILD_OUTPUT}/efi/boot/"
1233 mv "${CHROOT_OUTPUT}/var/lib/grml_live_bootx64.efi" "${BUILD_OUTPUT}/efi/boot/bootx64.efi"
1237 if [ -r "${BUILD_OUTPUT}"/boot/efi.img ] ; then
1238 einfo "/boot/efi.img found and amd64 architecture present, extending boot arguments."
1239 log "/boot/efi.img found and amd64 architecture present, extending boot arguments."
1240 BOOT_ARGS="$BOOT_ARGS -boot-info-table -eltorito-alt-boot -e boot/efi.img -no-emul-boot"
1252 if cd "$BUILD_OUTPUT" ; then
1253 if [ "$BOOT_METHOD" = "grub2" ]; then
1254 # make a 2048-byte bootsector for El Torito
1255 dd if=/dev/zero of=boot/grub/toriboot.bin bs=512 count=4 2>/dev/null
1256 # those are in 2048-byte sectors, so 1 16 matches 4 63 below
1257 echo 1 16 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -B 11 | \
1258 dd of=boot/grub/toriboot.bin conv=notrunc 2>/dev/null
1260 log "$MKISOFS -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J $BOOT_ARGS -o ${ISO_OUTPUT}/${ISO_NAME} ."
1261 $MKISOFS -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1262 -l -r -J $BOOT_ARGS -no-pad \
1263 -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1264 # both of these need core.img there, so it’s easier to write it here
1265 if [ "$BOOT_METHOD" = "grub2" ] || [ "$HYBRID_METHOD" = "grub2" ]; then
1266 # must be <= 30720 bytes
1267 dd if=boot/grub/core.img of="${ISO_OUTPUT}/${ISO_NAME}" \
1268 conv=notrunc bs=512 seek=4 2>/dev/null
1271 # pad the output ISO to multiples of 256 KiB for partition table support
1272 siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1273 cyls=$((siz / 512 / 32 / 16 + 1)) # C=$cyls H=16 S=32
1274 siz=$((cyls * 16 * 32 * 512)) # size after padding
1275 dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1276 of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1278 # support disabling hybrid ISO image
1279 if [ "$HYBRID_METHOD" = "disable" ] ; then\
1280 log "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1281 einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1283 elif [ "$HYBRID_METHOD" = "manifold" ] ; then
1284 # isoinfo is part of both mkisofs and genisoimage so we're good
1285 bootoff=$(isoinfo -l -i "${ISO_OUTPUT}/${ISO_NAME}" | \
1286 sed -n '/^.*\[ *\([0-9]*\)[] ].* ISOLINUX.BIN[;1]* *$/s//\1/p')
1287 if ! [ -r boot/grub/core.img ] ; then
1288 ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1289 elif [ "${bootoff:-0}" -lt 1 ] ; then
1290 ewarn "isolinux.bin not found on the ISO file, disabling manifold boot"
1292 log "Creating hybrid ISO file with manifold method"
1293 einfo "Creating hybrid ISO file with manifold method"
1294 if [ "$HYBRID_METHOD" = "grub2" ] ; then
1295 # 512 bytes: MBR, partition table, load GRUB 2
1296 echo 4 63 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 4:0x96 -g $cyls:16:32
1298 # read only one but 2048-byte sized (scale: << 2) sector
1299 echo $bootoff $bootoff | \
1300 mksh /usr/share/grml-live/scripts/bootilnx.mksh -A -M 4:0x96 -g $cyls:16:32 -S 2
1301 fi | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1304 # use isohybrid as default
1306 if ! which isohybrid >/dev/null 2>&1 ; then
1307 bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1309 log "Creating hybrid ISO file with isohybrid method"
1310 einfo "Creating hybrid ISO file with isohybrid method"
1311 # Notes for consideration:
1312 # "-entry 4 -type 1c"
1313 # * using 4 as the partition number is supposed to help with BIOSes
1314 # that only support USB-Zip boot
1315 # * using 1c (i.e. hidden FAT32 LBA), instead of the default 0x17
1316 # (hidden NTFS, IIRC), as the partition type is sometimes needed
1317 # to get the BIOS even look at the partition created by isohybrid
1318 if isohybrid --help | grep -q -- --uefi ; then
1319 einfo "Detected uefi support for isohybrid, enabling."
1320 ISOHYBRID_OPTIONS=--uefi
1323 log "isohybrid $ISOHYBRID_OPTIONS ${ISO_OUTPUT}/${ISO_NAME}"
1324 isohybrid $ISOHYBRID_OPTIONS "${ISO_OUTPUT}/${ISO_NAME}"
1329 # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1330 case $CLASSES in *RELEASE*)
1333 if cd $ISO_OUTPUT ; then
1334 md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1335 touch -r ${ISO_NAME} ${ISO_NAME}.md5
1336 sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1337 touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1346 if [ "$RC" = 0 ] ; then
1347 log "Finished execution of stage 'iso build' [$(date)]"
1348 einfo "Finished execution of stage 'iso build'" ; eend 0
1350 log "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1351 eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1357 # netboot package {{{
1358 create_netbootpackage() {
1359 local OUTPUT_FILE="${NETBOOT}/grml_netboot_package_${GRML_NAME}_${VERSION}.tar.bz2"
1361 if [ -f "${OUTPUT_FILE}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
1362 log "Skipping stage 'netboot' as $OUTPUT_FILE exists already."
1363 ewarn "Skipping stage 'netboot' as $OUTPUT_FILE exists already." ; eend 0
1365 elif [ -n "$SKIP_NETBOOT" ] ; then
1366 log "Skipping stage 'netboot' as requested via option -Q"
1367 ewarn "Skipping stage 'netboot' as requested via option -Q" ; eend 0
1373 if ! [ -r "${CHROOT}/usr/lib/syslinux/pxelinux.0" ] ; then
1374 ewarn "File /usr/lib/syslinux/pxelinux.0 not found in build chroot." ; eend 0
1376 einfo "Install syslinux[-common] package in chroot to get a netboot package."
1381 local OUTPUTDIR="${NETBOOT}/build_tmp"
1382 local WORKING_DIR="${OUTPUTDIR}/grml_netboot_package_${GRML_NAME}_${VERSION}/tftpboot/"
1384 mkdir -p "$WORKING_DIR"
1386 cp "${CHROOT_OUTPUT}"/boot/vmlinuz-* "$WORKING_DIR"/vmlinuz
1387 cp "${CHROOT_OUTPUT}"/boot/initrd.img-* "$WORKING_DIR"/initrd.img
1388 cp "${CHROOT_OUTPUT}"/usr/lib/syslinux/pxelinux.0 "${WORKING_DIR}/pxelinux.0"
1390 mkdir -p "${WORKING_DIR}/pxelinux.cfg"
1391 if [ -r "${BUILD_OUTPUT}/boot/isolinux/netboot.cfg" ] ; then
1392 cp "${BUILD_OUTPUT}/boot/isolinux/netboot.cfg" "${WORKING_DIR}/pxelinux.cfg/default"
1394 ewarn "File ${BUILD_OUTPUT}/boot/isolinux/netboot.cfg not found." ; eend 0
1397 if tar -C "$OUTPUTDIR" -jcf "${OUTPUT_FILE}" "grml_netboot_package_${GRML_NAME}_${VERSION}" ; then
1398 sha1sum "${OUTPUT_FILE}" > "${OUTPUT_FILE}.sha1"
1399 einfo "Generated netboot package ${OUTPUT_FILE}" ; eend 0
1400 rm -rf "${OUTPUTDIR}"
1402 rm -rf "${OUTPUTDIR}"
1403 eerror "Could not generate netboot package ${OUTPUT_FILE}" ; eend 1
1408 create_netbootpackage
1411 # log build information to database if grml-live-db is installed and enabled {{{
1413 if [ -d /usr/share/grml-live-db ] ; then
1416 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1417 [ -n "$DPKG_DATABASE" ] || DPKG_DATABASE=/var/log/grml-live.db
1418 [ -n "$DPKG_DBSCRIPT" ] || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1419 [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1421 if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1422 log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1423 eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1427 # disable by default for now, not sure whether really everyone is using a local db file
1428 #if ! touch "$DPKG_DATABASE" ; then
1429 # eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1433 if ! [ -r "$DPKG_LIST" ] ; then
1434 log "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1435 ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1437 einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1438 log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1439 log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1442 if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1458 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1459 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1461 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1463 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1467 ## END OF FILE #################################################################
1468 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2