d04f6f57f7ae4c404ae2382f1a4f146eb18a13dd
[grml-live.git] / grml-live
1 #!/bin/bash
2 # Filename:      grml-live
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 ################################################################################
10
11 # some misc and global stuff {{{
12 export LANG=C
13 export LC_ALL=C
14
15 # define function getfilesize before "set -e"
16 if stat --help >/dev/null 2>&1; then
17   getfilesize='stat -c %s'  # GNU stat
18 else
19   getfilesize='stat -f %z'  # BSD stat
20 fi
21
22 # exit on any error:
23 # disable for now since it seems to cause some problems
24 # set -e
25
26 # global variables
27 GRML_LIVE_VERSION='0.16.1'
28 PN="$(basename $0)"
29 CMDLINE="$0 $@"
30 ADDONS_LIST_FILE='/boot/isolinux/addons_list.cfg'
31 # }}}
32
33 # usage information {{{
34 usage()
35 {
36   echo "
37 $PN - build process script for generating a (grml based) Linux Live-ISO
38
39 Usage: $PN [options, see as follows]
40
41    -a <architecture>       architecture; available values: i386 and amd64
42    -A                      ensure clean build and pack artifacts
43    -b                      build the ISO without updating the chroot via FAI
44    -B                      build the ISO without touching the chroot (skips cleanup)
45    -c <classe[s]>          classes to be used for building the ISO via FAI
46    -C <configfile>         configuration file for grml-live
47    -d <date>               use specified date instead of build time as date of release
48    -D <configdir>          use specified configuration directory instead of /etc/grml/fai
49    -F                      force execution without prompting
50    -g <grml_name>          set the grml flavour name
51    -h                      display short usage information and exit
52    -i <iso_name>           name of ISO
53    -I <src_directory>      directory which provides files that should become
54                            part of the chroot/ISO
55    -n                      skip generation of ISO
56    -N                      bootstrap (build chroot) only, do not create files for ISO
57    -o <output_directory>   main output directory of the build process
58    -q                      skip mksquashfs
59    -r <release_name>       release name
60    -s <suite>              Debian suite; values: etch, lenny, squeeze, sid
61    -t <template_directory> place of the templates
62    -u                      update existing chroot instead of rebuilding it from scratch
63    -U <username>           arrange output to be owned by specified username
64    -v <version_number>     specify version number of the release
65    -V                      increase verbosity in the build process
66    -z                      use ZLIB instead of LZMA/XZ compression
67
68 Usage examples:
69
70     $PN
71     $PN -c GRMLBASE,GRML_FULL,AMD64 -o /dev/shm/grml
72     $PN -c GRMLBASE,GRML_FULL,AMD64 -i grml_0.0-1.iso -v 0.0-1
73     $PN -c GRMLBASE,GRML_FULL,AMD64 -s sid -V -r 'grml-live rocks'
74
75 More details: man grml-live + /usr/share/doc/grml-live/grml-live.html
76               http://grml.org/grml-live/
77
78 Please send your bug reports and feedback to the grml-team: http://grml.org/bugs/
79 "
80 }
81
82 # make sure it's possible to get usage information without being
83 # root or actually executing the script
84 if [ "$1" = '-h' -o "$1" = '--help' ] ; then
85    usage
86    [ "$(id -u 2>/dev/null)" != 0 ] && echo "Please notice that this script requires root permissions."
87    exit 0
88 fi
89 # }}}
90
91 # some runtime checks {{{
92 # we need root permissions for the build-process:
93 if [ "$(id -u 2>/dev/null)" != 0 ] ; then
94    echo "Error: please run this script with uid 0 (root)." >&2
95    exit 1
96 fi
97
98 if [ -r /var/run/fai/FAI_INSTALLATION_IN_PROGRESS ] ; then
99    echo "/usr/sbin/fai already running or was aborted before.">&2
100    echo "You may remove /var/run/fai/FAI_INSTALLATION_IN_PROGRESS and try again.">&2
101    exit 1
102 fi
103
104 # see #449236
105 if [ -r /var/run/fai/fai_softupdate_is_running ] ; then
106    echo "/usr/sbin/fai softupdate already running or was aborted before.">&2
107    echo "You may remove /var/run/fai/fai_softupdate_is_running and try again.">&2
108    exit 1
109 fi
110 # }}}
111
112 # lsb-functions and configuration stuff {{{
113 # make sure they are not set by default
114 VERBOSE=''
115 FORCE=''
116 UPDATE=''
117 BUILD_ONLY=''
118 BUILD_DIRTY=''
119 BOOTSTRAP_ONLY=''
120 HOSTNAME=''
121
122 # don't use colors/escape sequences
123 if [ -r /lib/lsb/init-functions ] ; then
124   . /lib/lsb/init-functions
125   ! log_use_fancy_output && NOCOLORS=true
126 fi
127
128 if [ -r /etc/grml/lsb-functions ] ; then
129    . /etc/grml/lsb-functions
130 else
131    einfo()  { echo "  [*] $*" ;}
132    eerror() { echo "  [!] $*">&2 ;}
133    ewarn()  { echo "  [x] $*" ;}
134    eend()   { return 0 ;}
135    eindent()  { return 0 ;}
136    eoutdent() { return 0 ;}
137 fi
138
139 # source main configuration file:
140 LIVE_CONF=/etc/grml/grml-live.conf
141 . $LIVE_CONF
142 # }}}
143
144 # umount all directories {{{
145 umount_all() {
146    # make sure we don't leave any mounts - FAI doesn't remove them always
147    umount $CHROOT_OUTPUT/proc 2>/dev/null || /bin/true
148    umount $CHROOT_OUTPUT/sys  2>/dev/null || /bin/true
149    umount $CHROOT_OUTPUT/dev/pts 2>/dev/null || /bin/true
150    umount $CHROOT_OUTPUT/dev 2>/dev/null || /bin/true
151
152    # certain FAI versions sadly leave a ramdisk behind, so better safe than sorry
153    if [ -x /usr/lib/fai/mkramdisk ] ; then
154      /usr/lib/fai/mkramdisk -u "$(realpath ${CHROOT_OUTPUT}/var/lib/dpkg)" >/dev/null 2>&1 || /bin/true
155    fi
156
157    umount "${CHROOT_OUTPUT}/grml-live/sources/" 2>/dev/null || /bin/true
158    [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
159 }
160 # }}}
161
162 # clean exit {{{
163 bailout() {
164   rm -f /var/run/fai/fai_softupdate_is_running \
165         /var/run/fai/FAI_INSTALLATION_IN_PROGRESS
166   [ -n "$SQUASHFS_STDERR" ]  && rm -rf "$SQUASHFS_STDERR"
167   umount_all
168   [ -n "$1" ] && EXIT="$1" || EXIT="1"
169   [ -n "$2" ] && eerror "$2">&2
170   if [ -n "$PACK_ARTIFACTS" ]; then
171     log "Cleaning up"
172     einfo "Cleaning up"
173     [ -n "${BUILD_OUTPUT}"  -a -d "${BUILD_OUTPUT}"  ] && rm -r "${BUILD_OUTPUT}"
174     [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && rm -r "${CHROOT_OUTPUT}"
175     eend 0
176   fi
177   if [ -n "$CHOWN_USER" ]; then
178     log "Setting ownership"
179     einfo "Setting ownership"
180     [ -n "${OUTPUT}"         -a -d "${OUTPUT}"         ] && chown -R "${CHOWN_USER}:" "${OUTPUT}"
181     [ -n "${BUILD_OUTPUT}"   -a -d "${BUILD_OUTPUT}"   ] && chown -R "${CHOWN_USER}:" "${BUILD_OUTPUT}"
182     [ -n "${CHROOT_OUTPUT}"  -a -d "${CHROOT_OUTPUT}"  ] && chown -R "${CHOWN_USER}:" "${CHROOT_OUTPUT}"
183     [ -n "${ISO_OUTPUT}"     -a -d "${ISO_OUTPUT}"     ] && chown -R "${CHOWN_USER}:" "${ISO_OUTPUT}"
184     [ -n "${LOG_OUTPUT}"     -a -d "${LOG_OUTPUT}"     ] && chown -R "${CHOWN_USER}:" "${LOG_OUTPUT}"
185     [ -n "${CHROOT_ARCHIVE}" -a -f "${CHROOT_ARCHIVE}" ] && chown -R "${CHOWN_USER}:" "${CHROOT_ARCHIVE}"
186     eend 0
187   fi
188   log "------------------------------------------------------------------------------"
189   exit "$EXIT"
190 }
191 trap bailout 1 2 3 3 6 9 14 15
192 trap umount_all EXIT
193 # }}}
194
195 # some important functions {{{
196
197 # log output:
198 # usage: log "string to log"
199 log() { echo "$*" >> $LOGFILE ; }
200
201 # cut string at character number int = $1
202 # usage: cut_string 5 "1234567890" will output "12345"
203 cut_string() {
204   [ -n "$2" ] || return 1
205   echo "$2" | head -c "$1"; echo -ne "\n"
206 }
207
208 # prepend int = $1 spaces before string = $2
209 # usage: extend_string_begin 5 "123" will output "  123"
210 extend_string_begin() {
211   [ -n "$2" ] || return 1
212   local COUNT="$(echo $2 | wc -c)"
213   local FILL="$(expr $COUNT - $1)"
214   while [ "$FILL" -gt 1 ] ; do
215     echo -n " "
216     local FILL=$(expr $FILL - 1)
217   done
218   while [ "$FILL" -lt 1 ] ; do
219     echo -n " "
220     local FILL=$(expr $FILL + 1)
221   done
222   echo "$2" | head -c "$1"; echo -ne "\n"
223 }
224
225 # append int = $1 spaces to string = $2
226 # usage: extend_string_begin 5 "123" will output "123  "
227 extend_string_end() {
228   [ -n "$2" ] || return 1
229   echo -n "$2" | head -c "$1"
230   local COUNT="$(echo $2 | wc -c)"
231   local FILL="$(expr $COUNT - $1)"
232   while [ "$FILL" -gt 1 ] ; do
233     echo -n " "
234     local FILL=$(expr $FILL - 1)
235   done
236   while [ "$FILL" -lt 1 ] ; do
237     echo -n " "
238     local FILL=$(expr $FILL + 1)
239   done
240   echo -ne "\n"
241 }
242
243 # Copy addonfile $1 from either
244 #   * the chroot (via $2, the system path),
245 #   * or from TEMPLATE_DIRECTORY/compat (if exists),
246 #   * or from the host system (again, using $2),
247 # or warn about the missing file.
248 #
249 # This is because:
250 #   * We assume that the chroot always has a "good" version of
251 #     the file. Also it makes sources handling easier.
252 #   * On unstable, we Recommend the Debian packages containing
253 #     these files. The user can override them by putting his
254 #     "better" version into the chroot.
255 #   * On stable, the Debian packages are probably not available,
256 #     or outdated, so we look in TEMPLATE_DIRECTORY/compat first, where
257 #     our grml-live-compat package installs current file versions.
258 copy_addon_file() {
259   DEST="${BUILD_OUTPUT}/boot/$3"
260   if [ ! -d "${DEST}/" ]; then
261     mkdir -p "${DEST}"
262   fi
263   if [ -e "$CHROOT_OUTPUT/$2/$1" ]; then
264     log   "Copying $1 from chroot"
265     cp "$CHROOT_OUTPUT/$2/$1" "${DEST}/"
266     return $?
267   fi
268   if [ -e "${TEMPLATE_DIRECTORY}/compat/$3/$1" ]; then
269     log   "Copying $1 from grml-live-compat"
270     cp "${TEMPLATE_DIRECTORY}/compat/$3/$1" "${DEST}/"
271     return $?
272   fi
273   if [ -e "$2/$1" ]; then
274     log   "Copying $1 from system"
275     cp "$2/$1" "${DEST}/"
276     return $?
277   fi
278
279   msg="Missing addon file: \"$1\""
280   ewarn "$msg" ; eend 1
281   log "copy_addon_file: $msg"
282 }
283 # }}}
284
285 # read local (non-packaged) configuration {{{
286 LOCAL_CONFIG=/etc/grml/grml-live.local
287 if [ -r "$LOCAL_CONFIG" ] ; then
288    . $LOCAL_CONFIG
289 else
290    LOCAL_CONFIG=''
291 fi
292
293 if [ -n "${GRML_LIVE_SOURCES:-}" ] ; then
294   eerror "Config variable \$GRML_LIVE_SOURCES is set. This variable has been deprecated."
295   ewarn  "Please set up ${GRML_FAI_CONFIG}/config/files/etc/apt/sources.list.d/* instead."
296   bailout 1
297 fi
298 # }}}
299
300 # command line parsing {{{
301 while getopts "a:C:c:d:D:g:i:I:o:r:s:t:U:v:AbBFnNquVz" opt; do
302   case "$opt" in
303     a) ARCH="$OPTARG" ;;
304     A) PACK_ARTIFACTS=1 ;;
305     b) BUILD_ONLY=1 ;;
306     B) BUILD_DIRTY=1 ;;
307     c) CLASSES="$OPTARG" ;;
308     C) CONFIG="$OPTARG" ;;
309     d) DATE="$OPTARG" ;;
310     D) GRML_FAI_CONFIG="$OPTARG" ;;
311     g) GRML_NAME="$OPTARG" ;;
312     i) ISO_NAME="$OPTARG" ;;
313     I) CHROOT_INSTALL="$OPTARG" ;;
314     n) SKIP_MKISOFS=1 ;;
315     N) BOOTSTRAP_ONLY=1; SKIP_MKISOFS=1; SKIP_MKSQUASHFS=1 ;;
316     o) OUTPUT="$OPTARG" ;;
317     q) SKIP_MKSQUASHFS=1 ;;
318     r) RELEASENAME="$OPTARG" ;;
319     s) SUITE="$OPTARG" ;;
320     t) TEMPLATE_DIRECTORY="$OPTARG";;
321     v) VERSION="$OPTARG" ;;
322     F) FORCE=1 ;;
323     u) UPDATE=1 ;;
324     U) CHOWN_USER="$OPTARG" ;;
325     V) VERBOSE="-v" ;;
326     z) SQUASHFS_ZLIB=1 ;;
327     ?) echo "invalid option -$OPTARG" >&2; bailout 1 ;;
328   esac
329 done
330 shift $(($OPTIND - 1))  # set ARGV to the first not parsed commandline parameter
331 # }}}
332
333 # assume sane defaults (if not set already) {{{
334 [ -n "$ARCH" ]                    || ARCH="$(dpkg --print-architecture)"
335 [ -n "$BOOT_METHOD" ]             || BOOT_METHOD='isolinux'
336 [ -n "$CLASSES" ]                 || CLASSES="GRMLBASE,GRML_FULL,$(echo ${ARCH} | tr 'a-z' 'A-Z')"
337 [ -n "$DATE" ]                    || DATE="$(date +%Y-%m-%d)"
338 [ -n "$DISTRI_INFO" ]             || DISTRI_INFO='Grml - Live Linux for system administrators   '
339 [ -n "$DISTRI_NAME" ]             || DISTRI_NAME="grml"
340 [ -n "$DISTRI_SPLASH" ]           || DISTRI_SPLASH='grml.png'
341 [ -n "$FORCE_ISO_REBUILD" ]       || FORCE_ISO_REBUILD="false"
342 [ -n "$GRML_FAI_CONFIG" ]         || GRML_FAI_CONFIG='/etc/grml/fai'
343 [ -n "$GRML_NAME" ]               || GRML_NAME='grml'
344 [ -n "$HOSTNAME" ]                || HOSTNAME='grml'
345 [ -n "$HYBRID_METHOD" ]           || HYBRID_METHOD='manifold'
346 [ -n "$NFSROOT_CONF" ]            || NFSROOT_CONF="${GRML_FAI_CONFIG}/make-fai-nfsroot.conf"
347 [ -n "$RELEASENAME" ]             || RELEASENAME='grml-live rocks'
348 [ -n "$SQUASHFS_EXCLUDES_FILE" ]  || SQUASHFS_EXCLUDES_FILE="${GRML_FAI_CONFIG}/config/grml/squashfs-excludes"
349 [ -n "$SUITE" ]                   || SUITE='squeeze'
350 [ -n "$TEMPLATE_DIRECTORY" ]      || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
351 [ -n "$USERNAME" ]                || USERNAME='grml'
352 [ -n "$VERSION" ]                 || VERSION='0.0.1'
353
354 # output specific stuff, depends on $OUTPUT (iff not set):
355 [ -n "$OUTPUT" ]           || OUTPUT='/grml/grml-live'
356 [ -n "$BUILD_OUTPUT" ]     || BUILD_OUTPUT="$OUTPUT/grml_cd"
357 [ -n "$CHROOT_OUTPUT" ]    || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
358 [ -n "$CHROOT_ARCHIVE" ]   || CHROOT_ARCHIVE="$OUTPUT/$(basename $CHROOT_OUTPUT).tgz"
359 [ -n "$ISO_OUTPUT" ]       || ISO_OUTPUT="$OUTPUT/grml_isos"
360 [ -n "$LOG_OUTPUT" ]       || LOG_OUTPUT="$OUTPUT/grml_logs"
361 # }}}
362
363 # some misc checks before executing FAI {{{
364 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
365 specify it on the command line using the -c option."
366 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
367 specify it on the command line using the -o option."
368
369 # trim characters that are known to cause problems inside $GRML_NAME;
370 # for example isolinux does not like '-' inside the directory name
371 [ -n "$GRML_NAME" ] && export SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
372
373 # export variables to have them available in fai scripts:
374 [ -n "$GRML_NAME" ]   && export GRML_NAME="$GRML_NAME"
375 [ -n "$RELEASENAME" ] && export RELEASENAME="$RELEASENAME"
376 # }}}
377
378 # ZERO_LOGFILE - check for backwards compatibility reasons {{{
379 # this was default behaviour until grml-live 0.9.34:
380 if [ -n "$ZERO_LOGFILE" ] ; then
381    PRESERVE_LOGFILE='' # make sure it's cleaned then
382    ewarn "Please consider disabling the \$ZERO_LOGFILE option as grml-live clears..."
383    ewarn "... the logfile $LOGFILE by default (unless \$PRESERVE_LOGFILE is set) nowadays."
384    eend 0
385 fi
386 # }}}
387
388 # ask user whether the setup is ok {{{
389 if [ -z "$FORCE" ] ; then
390    echo
391    echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
392    echo
393    echo "  FAI classes:       $CLASSES"
394    [ -r "$LOCAL_CONFIG" ]        && echo "  Local config:      /etc/grml/grml-live.local"
395    [ -n "$CONFIG" ]              && echo "  Configuration:     $CONFIG"
396    [ -n "$GRML_FAI_CONFIG" ]     && echo "  Config directory:  $GRML_FAI_CONFIG"
397    echo "  main directory:    $OUTPUT"
398    [ -n "$CHROOT_OUTPUT" ]       && echo "  Chroot target:     $CHROOT_OUTPUT"
399    [ -n "$BUILD_OUTPUT" ]        && echo "  Build target:      $BUILD_OUTPUT"
400    [ -n "$ISO_OUTPUT" ]          && echo "  ISO target:        $ISO_OUTPUT"
401    [ -n "$GRML_NAME" ]           && echo "  Grml name:         $GRML_NAME"
402    [ -n "$RELEASENAME" ]         && echo "  Release name:      $RELEASENAME"
403    [ -n "$DATE" ]                && echo "  Build date:        $DATE"
404    [ -n "$VERSION" ]             && echo "  Grml version:      $VERSION"
405    [ -n "$SUITE" ]               && echo "  Debian suite:      $SUITE"
406    [ -n "$ARCH" ]                && echo "  Architecture:      $ARCH"
407    [ -n "$BOOT_METHOD" ]         && echo "  Boot method:       $BOOT_METHOD"
408    [ -n "$HYBRID_METHOD" ]       && echo "  Hybrid method:     $HYBRID_METHOD"
409    [ -n "$TEMPLATE_DIRECTORY" ]  && echo "  Template files:    $TEMPLATE_DIRECTORY"
410    [ -n "$CHROOT_INSTALL" ]      && echo "  Install files from directory to chroot:  $CHROOT_INSTALL"
411    [ -n "$BOOTID" ]              && echo "  Boot identifier:   $BOOTID"
412    [ -n "$NO_BOOTID" ]           && echo "  Skipping bootid feature."
413    [ -n "$CHOWN_USER" ]          && echo "  Output owner:      $CHOWN_USER"
414    [ -n "$DEFAULT_BOOTOPTIONS" ] && echo "  Adding default bootoptions: \"$DEFAULT_BOOTOPTIONS\""
415    [ -n "$FAI_ARGS" ]            && echo "  Additional arguments for FAI: $FAI_ARGS"
416    [ -n "$LOGFILE" ]             && echo "  Logging to file:   $LOGFILE"
417    [ -n "$SQUASHFS_ZLIB" ]       && echo "  Using ZLIB (instead of LZMA/XZ) compression."
418    [ -n "$SQUASHFS_OPTIONS" ]    && echo "  Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
419    [ -n "$VERBOSE" ]             && echo "  Using VERBOSE mode."
420    [ -n "$PACK_ARTIFACTS" ]      && echo "  Will prepare packed artifacts and ensure clean build."
421    [ -n "$UPDATE" ]              && echo "  Executing UPDATE instead of fresh installation."
422    if [ -n "$BOOTSTRAP_ONLY" ] ; then
423      echo "  Bootstrapping only and not building (files for) ISO."
424    else
425      [ -n "$SKIP_MKSQUASHFS" ]     && echo "  Skipping creation of SQUASHFS file."
426      [ -n "$SKIP_MKISOFS" ]        && echo "  Skipping creation of ISO file."
427      [ -n "$BUILD_ONLY" ]          && echo "  Executing BUILD_ONLY instead of fresh installation or UPDATE."
428      [ -n "$BUILD_DIRTY" ]         && echo "  Executing BUILD_DIRTY to leave chroot untouched."
429    fi
430    echo
431    echo -n "Is this ok for you? [y/N] "
432    read a
433    if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
434       bailout 1 "Exiting as requested."
435    fi
436    echo
437 fi
438 # }}}
439
440 # clean up before start {{{
441 if [ -n "${PACK_ARTIFACTS}" ]; then
442   echo "Wiping old artifacts"
443   [ -n "${CHROOT_OUTPUT}"  -a -d "${CHROOT_OUTPUT}"  ] && rm -r "${CHROOT_OUTPUT}"
444   [ -n "${BUILD_OUTPUT}"   -a -d "${BUILD_OUTPUT}"   ] && rm -r "${BUILD_OUTPUT}"
445   [ -n "${ISO_OUTPUT}"     -a -d "${ISO_OUTPUT}"     ] && rm -r "${ISO_OUTPUT}"
446   [ -n "${LOG_OUTPUT}"     -a -d "${LOG_OUTPUT}"     ] && rm -r "${LOG_OUTPUT}"
447   [ -n "${CHROOT_ARCHIVE}" -a -f "${CHROOT_ARCHIVE}" ] && rm "${CHROOT_ARCHIVE}"
448 fi
449 # }}}
450
451 # create log file {{{
452 [ -n "$LOGFILE" ] || LOGFILE=${LOG_OUTPUT}/grml-live.log
453 mkdir -p $(dirname "${LOGFILE}")
454 touch $LOGFILE
455 chown root:adm $LOGFILE
456 chmod 664 $LOGFILE
457 # }}}
458
459 # clean/zero/remove logfiles {{{
460
461 if [ -n "$PRESERVE_LOGFILE" ] ; then
462    echo "Preserving logfile $LOGFILE as requested via \$PRESERVE_LOGFILE"
463 else
464    # make sure it is empty (as it is e.g. appended to grml-live-db)
465    echo -n > $LOGFILE
466 fi
467
468 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
469    if [ -d /var/log/fai/"$HOSTNAME" ] ; then
470       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
471       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
472       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
473       rm -f /var/log/fai/"$HOSTNAME"/last \
474             /var/log/fai/"$HOSTNAME"/last-dirinstall \
475             /var/log/fai/"$HOSTNAME"/last-softupdate
476    fi
477 fi
478 # }}}
479
480 # source config and startup {{{
481 if [ -n "$CONFIG" ] ; then
482    if ! [ -f "$CONFIG" ] ; then
483       log    "Error: $CONFIG could not be read. Exiting. [$(date)]"
484       eerror "Error: $CONFIG could not be read. Exiting." ; eend 1
485       bailout 1
486    else
487       log "Sourcing $CONFIG"
488       . $CONFIG
489    fi
490 fi
491
492 start_seconds=$(cut -d . -f 1 /proc/uptime)
493 log "------------------------------------------------------------------------------"
494 log "Starting grml-live [${GRML_LIVE_VERSION}] run on $(date)"
495 if [ -n "$LOCAL_CONFIG" ]; then
496   log "Using local config file: $LOCAL_CONFIG"
497 fi
498 log "Executed grml-live command line:"
499 log "$CMDLINE"
500
501 einfo "Logging actions to logfile $LOGFILE"
502 # }}}
503
504 # on-the-fly configuration {{{
505 if [ -n "$FAI_DEBOOTSTRAP" ] ; then
506   sed "s#^FAI_DEBOOTSTRAP=.*#FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"#" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
507 fi
508
509 # does this suck? YES!
510 # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
511 case $SUITE in
512    unstable) SUITE='sid' ; CLASSES="DEBIAN_UNSTABLE,$CLASSES" ;;
513    *) CLASSES="DEBIAN_$(echo $SUITE | tr 'a-z' 'A-Z'),$CLASSES";;
514 esac
515 export SUITE # make sure it's available in FAI scripts
516
517 for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" "$NFSROOT_CONF" ; do
518     if [ -n "$file" ] ; then
519        sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
520     fi
521 done
522
523 # validate whether the specified architecture class matches the
524 # architecture (option), otherwise installation of kernel will fail
525 if echo $CLASSES | grep -qi i386 ; then
526    if ! [[ "$ARCH" == "i386" ]] ; then
527       log    "Error: You specified the I386 class but are trying to build something else (AMD64?)."
528       eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
529       eerror "Tip:   Either invoke grml-live with '-a i386' or adjust the architecture class. Exiting."
530       eend 1
531       bailout
532    fi
533 elif echo $CLASSES | grep -qi amd64 ; then
534    if ! [[ "$ARCH" == "amd64" ]] ; then
535       log    "Error: You specified the AMD64 class but are trying to build something else (I386?)."
536       eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
537       eerror "Tip:   Either invoke grml-live with '-a amd64' or adjust the architecture class. Exiting."
538       eend 1
539       bailout
540    fi
541 fi
542
543 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
544    sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
545 else
546    sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
547 fi
548 # }}}
549
550 # CHROOT_OUTPUT - execute FAI {{{
551 if [ -n "$BUILD_DIRTY" ]; then
552    log   "Skipping stage 'fai' as requested via option -B"
553    ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
554 else
555    [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
556
557    # provide inform fai about the ISO we build
558    [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
559    echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
560    [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
561    [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
562
563    if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
564       FAI_ACTION=softupdate
565    else
566       FAI_ACTION=dirinstall
567    fi
568
569    if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
570       if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
571          log    "Error: does not look like you have a working chroot. Updating/building not possible."
572          eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
573          eend 1
574          bailout 20
575       fi
576    fi
577
578    if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
579       log   "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
580       ewarn "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
581    else
582       mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
583
584       if [ -n "${MIRROR_DIRECTORY}" ] ; then
585          mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
586          mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
587       fi
588
589       mkdir -p "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
590       mount --bind "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
591
592       # tell dpkg to use "unsafe io" during the build
593       [ -d "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d" ] || mkdir -p "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d"
594       echo force-unsafe-io > "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
595
596       log "Executed FAI command line:"
597       log "BUILD_ONLY=$BUILD_ONLY BOOTSTRAP_ONLY=$BOOTSTRAP_ONLY fai $VERBOSE -C $GRML_FAI_CONFIG -s file:///$GRML_FAI_CONFIG/config -c$CLASSES -u $HOSTNAME $FAI_ACTION $CHROOT_OUTPUT $FAI_ARGS"
598       BUILD_ONLY="$BUILD_ONLY" BOOTSTRAP_ONLY="$BOOTSTRAP_ONLY" fai $VERBOSE \
599                   -C "$GRML_FAI_CONFIG" -s "file:///$GRML_FAI_CONFIG/config" -c"$CLASSES" \
600                   -u "$HOSTNAME" "$FAI_ACTION" "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
601       RC="$PIPESTATUS" # notice: bash-only
602
603       rm -f "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
604
605       FORCE_ISO_REBUILD=true
606
607       if [ "$RC" != 0 ] ; then
608          log    "Error: critical error while executing fai [exit code ${RC}]. Exiting."
609          eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
610          bailout 1
611       else
612          einfo "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
613          log   "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
614          echo "$GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]" > $CHROOT_OUTPUT/etc/grml_version
615          chmod 644 $CHROOT_OUTPUT/etc/grml_version
616          einfo "Rebuilding initramfs"
617          # make sure new /etc/grml_version reaches initramfs, iterate over all
618          # present kernel versions (note: we can't really handle more than one
619          # kernel version anyway right now)
620          # chroot $CHROOT_OUTPUT update-initramfs -u -t => might break when using kernel-package :(
621          for initrd in "$(basename $CHROOT_OUTPUT/boot/vmlinuz-*)" ; do
622            if ! chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -c ; then
623              einfo "Creating fresh initrd did not work, trying update instead:"
624              log   "Creating fresh initrd did not work, trying update instead:"
625              chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -u
626            fi
627          done
628          eend $?
629       fi
630
631       # move fai logs into grml_logs directory
632       mkdir -p "$LOG_OUTPUT"/fai/
633       cp -r "$CHROOT_OUTPUT"/var/log/fai/"$HOSTNAME"/last/* "$LOG_OUTPUT"/fai/
634       chown root:adm "$LOG_OUTPUT"/fai/*
635       chmod 664 "$LOG_OUTPUT"/fai/*
636       rm -rf "$CHROOT_OUTPUT"/var/log/fai
637
638       # Remove all FAI logs from chroot if class RELEASE is used:
639       rm -f "$CHROOT_OUTPUT"/var/log/install_packages.list
640
641       umount_all
642
643       # notice: 'fai dirinstall' does not seem to exit appropriate, so:
644       ERROR=''
645       CHECKLOG=/var/log/fai/$HOSTNAME/last
646       if [ -r "$CHECKLOG/software.log" ] ; then
647          # 1 errors during executing of commands
648          grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
649          grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
650          grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
651          grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
652          grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
653       fi
654
655       if [ -r "$CHECKLOG/shell.log" ] ; then
656          grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=6
657       fi
658
659       if [ -n "$ERROR" ] ; then
660          log    "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
661          eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
662          eerror "Note:  check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
663          eend 1
664          bailout 1
665       else
666          log "Finished execution of stage 'fai dirinstall' [$(date)]"
667          einfo "Finished execution of stage 'fai dirinstall'"
668       fi
669
670       einfo "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
671       log   "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
672       eend 0
673    fi
674 fi # BUILD_DIRTY?
675 # }}}
676
677 # package validator {{{
678 CHECKLOG=/var/log/fai/$HOSTNAME/last
679 # package validator
680 if [ -r "$CHECKLOG/package_errors.log" ] && grep -q '[a-z]' "$CHECKLOG/package_errors.log" ; then
681
682    if [ -n "$EXIT_ON_MISSING_PACKAGES" -a -z "$BUILD_DIRTY" ] ; then
683       eerror "The following packages were requested for installation but could not be processed:"
684       cat $CHECKLOG/package_errors.log
685       eerror "... exiting as requested via \$EXIT_ON_MISSING_PACKAGES."
686       eend 1
687       bailout 13
688    else
689       ewarn "The following packages were requested for installation but could not be processed:"
690       cat $CHECKLOG/package_errors.log
691       eend 0
692    fi
693 fi
694 # }}}
695
696 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
697 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
698 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
699
700 # prepare ISO
701 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
702   if [ -n "$BOOTSTRAP_ONLY" ] ; then
703      log   "Skipping stage 'boot' as building with bootstrap only."
704      ewarn "Skipping stage 'boot' as building with bootstrap only." ; eend 0
705   else
706     if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
707        log   "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already."
708        ewarn "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already." ; eend 0
709     else
710        # booting stuff:
711        [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
712        [ -d "$BUILD_OUTPUT"/boot/"${SHORT_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
713
714        # if we don't have an initrd we a) can't boot and b) there was an error
715        # during build, so check for the file:
716        INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
717        if [ -n "$INITRD" ] ; then
718           cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.gz
719           find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
720        else
721           log    "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
722           eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
723           bailout 10
724        fi
725
726        KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
727        if [ -n "$KERNEL_IMAGE" ] ; then
728           cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/linux26
729        else
730           log    "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
731           eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
732           bailout 11
733        fi
734
735        [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
736        if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
737           log    "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
738           eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
739           bailout 8
740        fi
741
742        # copy _required_ isolinux files
743        for file in ifcpu64.c32 isolinux.bin vesamenu.c32; do
744          copy_addon_file "${file}" /usr/lib/syslinux isolinux
745        done
746
747        # *always* copy files to output directory so the variables
748        # get adjusted according to the build.
749        cp ${TEMPLATE_DIRECTORY}/boot/isolinux/*  "$BUILD_OUTPUT"/boot/isolinux/
750
751        if [ -n "$NO_ADDONS" ] ; then
752           log   "Skipping installation of boot addons as requested via \$NO_ADDONS."
753           einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
754        else
755           if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
756             log   "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
757             ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
758           else
759             # copy addons from system packages or grml-live-compat
760             copy_addon_file ipxe.lkrn /usr/lib/ipxe addons
761             copy_addon_file pci.ids /usr/share/misc addons
762             copy_addon_file memtest86+.bin /boot addons
763             for file in memdisk chain.c32 hdt.c32 menu.c32; do
764               copy_addon_file "${file}" /usr/lib/syslinux addons
765             done
766
767             # make memtest filename FAT16/8.3 compatible
768             mv "${BUILD_OUTPUT}/boot/addons/memtest86+.bin" \
769               "${BUILD_OUTPUT}/boot/addons/memtest"
770
771             # copy only files so we can handle bsd4grml on its own
772             for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
773               test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
774             done
775
776             if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
777                log   "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
778                einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
779             else
780                if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
781                  cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
782                else
783                  log   "Missing addon file: bsd4grml"
784                  ewarn "Missing addon file: bsd4grml" ; eend 0
785                fi
786             fi
787
788           fi # no "$TEMPLATE_DIRECTORY"/boot/addons
789        fi # NO_ADDONS
790
791        if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
792          mkdir -p "${BUILD_OUTPUT}/boot/grub"
793        fi
794        cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
795
796        if [ -e ${TEMPLATE_DIRECTORY}/compat/grub/linux.mod ]; then
797          cp "${TEMPLATE_DIRECTORY}"/compat/grub/* "${BUILD_OUTPUT}"/boot/grub/
798        else
799          if ! which "grub-mkimage" >/dev/null 2>&1 ; then
800            log   "grub-mkimage not found, skipping Grub step therefore." ; eend 0
801            ewarn "grub-mkimage not found, skipping Grub step therefore."
802            ewarn "Please install grub-pc-bin or grub-common >= 1.98+20100804-14." ; eend 0
803          elif ! grub-mkimage --help | grep -q -- --format ; then
804            log   "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore." ; eend 0
805            ewarn "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore."
806            ewarn "Please install grub-common >= 1.98+20100804-14 or grub-pc-bin." ; eend 0
807          else
808            # copy system grub files if grml-live-compat is not installed
809            cp -a /usr/lib/grub/*-pc/*.mod "${BUILD_OUTPUT}"/boot/grub/
810            cp -a /usr/lib/grub/*-pc/*.o "${BUILD_OUTPUT}"/boot/grub/
811            cp -a /usr/lib/grub/*-pc/*.lst "${BUILD_OUTPUT}"/boot/grub/
812            cp -a /usr/share/grub/ascii.pf2 "${BUILD_OUTPUT}"/boot/grub/
813            grub-mkimage -d /usr/lib/grub/*-pc -o \
814              "${BUILD_OUTPUT}/boot/grub/core.img" biosdisk iso9660 --format=i386-pc
815          fi
816        fi
817
818        if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
819           log    "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
820           eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
821           bailout 9
822        fi
823
824        [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
825        cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
826
827        # adjust boot splash information:
828        RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
829        RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
830        RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
831
832        if [ -r "$BUILD_OUTPUT"/GRML/grml-version ] ; then
833           sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
834           sed -i "s/%DATE%/$DATE/"                                      "$BUILD_OUTPUT"/GRML/grml-version
835        fi
836
837        # make sure the squashfs filename is set accordingly:
838        SQUASHFS_NAME="$GRML_NAME.squashfs"
839
840        if [ -n "$NO_BOOTID" ] ; then
841           log   'Skipping bootid feature as requested via $NO_BOOTID.'
842           einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
843        else
844           [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
845           [ -d "$BUILD_OUTPUT"/conf ] || mkdir "$BUILD_OUTPUT"/conf
846           einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
847           log   "Generating /conf/bootid.txt with entry ${BOOTID}."
848           echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
849           eend $?
850        fi
851
852        # adjust all variables in the templates with the according distribution information
853        for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
854                    "${BUILD_OUTPUT}"/boot/grub/* ; do
855          if [ -r "${file}" ] ; then
856            sed -i "s/%ARCH%/$ARCH/g"                    "${file}"
857            sed -i "s/%DATE%/$DATE/g"                    "${file}"
858            sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g"      "${file}"
859            sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g"      "${file}"
860            sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g"  "${file}"
861            sed -i "s/%GRML_NAME%/$GRML_NAME/g"          "${file}"
862            sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g"  "${file}"
863            sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g"    "${file}"
864            sed -i "s/%SHORT_NAME%/$SHORT_NAME/g"        "${file}"
865            sed -i "s/%VERSION%/$VERSION/g"              "${file}"
866
867            [ -n "$DEFAULT_BOOTOPTIONS" ] && sed -i "s/ boot=live/ boot=live $DEFAULT_BOOTOPTIONS/"  "${file}"
868
869            if [ -n "$NO_BOOTID" ] ; then
870               sed -i "s/ bootid=%BOOTID%//g" "${file}" # drop bootid bootoption
871            else
872               sed -i "s/%BOOTID%/$BOOTID/g" "${file}" # adjust bootid=... argument
873            fi
874          fi
875        done
876
877        # adjust bootsplash accordingly but make sure the string has the according lenght
878        SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
879        SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
880        for file in f4 f5 ; do
881           if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
882              sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
883              sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
884           fi
885        done
886
887        # generate addon list
888        rm -f "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
889        for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
890          include_name=$(basename "$name")
891          echo "include $include_name"  >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
892        done
893
894        if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
895           log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
896           echo "include grmlmain.cfg"    >  "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
897           echo "include default.cfg"     >  "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
898           echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
899           echo "include grml.cfg"        >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
900
901           for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
902             echo "include $(basename $f)"     >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
903           done
904
905           echo "include options.cfg"     >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
906           if [ ! -n "$NO_ADDONS" ] ; then
907             echo "include addons.cfg"    >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
908           fi
909           echo "include isoprompt.cfg"   >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
910           echo "include hd.cfg"          >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
911           echo "include hidden.cfg"      >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
912        else # assume we are building a custom distribution:
913           log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
914           einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
915           if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
916             log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
917             eindent
918             einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
919             eoutdent
920             eend $?
921          else
922             log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
923             echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
924             [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
925           fi
926        fi
927
928        # use old style console based isolinux method only if requested:
929        if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
930           log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
931           einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
932           if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
933             einfo "include for console.cfg already found, nothing to do."
934             eend 0
935           else
936             log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
937             einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
938             echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
939             eend $?
940           fi
941        else
942           log 'Using graphical boot menu.'
943           if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
944             log "include for vesamenu.cfg already found, nothing to do."
945           else
946             log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
947             echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
948           fi
949        fi
950
951        if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
952           sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
953        fi
954
955        DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
956        if ! [ -r "$DPKG_LIST" ] ; then
957           ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
958        else
959           einfo "Storing package list information as /GRML/${GRML_NAME}-packages.txt on ISO."
960           cp "$DPKG_LIST" "${BUILD_OUTPUT}/GRML/${GRML_NAME}-packages.txt"
961           eend $?
962        fi
963
964        # autostart for Windows:
965        if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
966           cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
967        fi
968
969     FORCE_ISO_REBUILD=true
970     einfo "Finished execution of stage 'boot'" ; eend 0
971     fi
972   fi # BOOTSTRAP_ONLY
973 else
974    log    'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
975    eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
976    bailout
977 fi
978
979 # support installation of local files into the chroot/ISO
980 if [ -n "$CHROOT_INSTALL" ] ; then
981   if ! [ -d "$CHROOT_INSTALL" ] ; then
982      log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
983      ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
984   else
985      log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
986      einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
987      rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
988      eend $?
989      einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
990      FORCE_ISO_REBUILD=true
991   fi
992 fi
993
994 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
995    log   "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
996    ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
997 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
998    log   "Skipping stage 'squashfs' as requested via option -q or -N"
999    ewarn "Skipping stage 'squashfs' as requested via option -q or -N" ; eend 0
1000 else
1001    [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
1002    # make sure we don't leave (even an empty) base.tgz:
1003    [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
1004
1005    # if unconfigured default to squashfs-tools' mksquashfs binary
1006    if [ -z "$SQUASHFS_BINARY" ] ; then
1007       SQUASHFS_BINARY='mksquashfs'
1008    fi
1009
1010    if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
1011       log    "Using mksquashfs binary ${SQUASHFS_BINARY}"
1012       einfo  "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
1013    else
1014       log    "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
1015       eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
1016       bailout
1017    fi
1018
1019    # use sane defaults if $SQUASHFS_OPTIONS isn't set
1020    if [ -z "$SQUASHFS_OPTIONS" ] ; then
1021      # use blocksize 256k as this gives best result with regards to time + compression
1022      SQUASHFS_OPTIONS="-b 256k"
1023
1024      # set lzma/xz compression by default, unless -z option has been specified on command line
1025      if [ -z "$SQUASHFS_ZLIB" ] ; then
1026         SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp xz"
1027      else
1028         SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp gzip"
1029      fi
1030    fi
1031
1032    # support exclusion of files via exclude-file:
1033    if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
1034       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE -wildcards"
1035    fi
1036
1037    # get rid of unnecessary files when building grml-small for final release:
1038    if echo "$CLASSES" | grep -q GRML_SMALL ; then
1039       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
1040    fi
1041
1042    # log stuff
1043    SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
1044
1045    # informational stuff
1046    [ -n "$SQUASHFS_OPTIONS" ]  && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
1047    [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
1048    einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
1049
1050    log "$SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS"
1051
1052    if $SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
1053       -noappend $SQUASHFS_OPTIONS 2>"${SQUASHFS_STDERR}" ; then
1054       echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
1055       log "Finished execution of stage 'squashfs' [$(date)]"
1056       einfo "Finished execution of stage 'squashfs'" ; eend 0
1057    else
1058       log    "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1059       log    "$(cat $SQUASHFS_STDERR)"
1060       eerror "Error: there was a critical error executing stage 'squashfs':"
1061       cat    "${SQUASHFS_STDERR}"
1062       eend 1
1063       bailout
1064    fi
1065
1066    FORCE_ISO_REBUILD=true
1067 fi
1068
1069 # create md5sum file:
1070 if [ -z "$BOOTSTRAP_ONLY" ] ; then
1071   ( cd $BUILD_OUTPUT/GRML &&
1072   find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1073 fi
1074 # }}}
1075
1076 # ISO_OUTPUT - mkisofs {{{
1077 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1078 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1079
1080 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1081    BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1082 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1083    BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1084 fi
1085
1086 # Just until http://bts.grml.org/grml/issue945 has been resolved.
1087 # HYBRID_METHOD defaults to manifold, so make sure the default works OOTB.
1088 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1089   log   "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1090   ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1091   HYBRID_METHOD='grub2'
1092   eend 0
1093 fi
1094
1095 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ]  ; then
1096    log   "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1097    ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1098 elif [ -n "$SKIP_MKISOFS" ] ; then
1099    log   "Skipping stage 'iso build' as requested via option -n or -N"
1100    ewarn "Skipping stage 'iso build' as requested via option -n or -N" ; eend 0
1101 else
1102    mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1103
1104    if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1105       log   "Forcing rebuild of ISO because files on ISO have been modified."
1106       einfo "Forcing rebuild of ISO because files on ISO have been modified."
1107    fi
1108
1109    # support mkisofs as well as genisoimage
1110    if which mkisofs >/dev/null 2>&1; then
1111       MKISOFS='mkisofs'
1112    elif which genisoimage >/dev/null 2>&1; then
1113       MKISOFS='genisoimage'
1114    else
1115       log    "Error: neither mkisofs nor genisoimage available - can not create ISO."
1116       eerror "Error: neither mkisofs nor genisoimage available - can not create ISO." ; eend 1
1117       bailout
1118    fi
1119
1120    CURRENT_DIR=$(pwd)
1121    if cd "$BUILD_OUTPUT" ; then
1122       if [ "$BOOT_METHOD" = "grub2" ]; then
1123          # make a 2048-byte bootsector for El Torito
1124          dd if=/dev/zero of=boot/grub/toriboot.bin bs=512 count=4 2>/dev/null
1125          # those are in 2048-byte sectors, so 1 16 matches 4 63 below
1126          echo 1 16 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -B 11 | \
1127             dd of=boot/grub/toriboot.bin conv=notrunc 2>/dev/null
1128       fi
1129       log "$MKISOFS -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J $BOOT_ARGS -o ${ISO_OUTPUT}/${ISO_NAME} ."
1130       "$MKISOFS" -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1131               -l -r -J $BOOT_ARGS -no-pad \
1132               -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1133       # both of these need core.img there, so it’s easier to write it here
1134       if [ "$BOOT_METHOD" = "grub2" ] || [ "$HYBRID_METHOD" = "grub2" ]; then
1135          # must be <= 30720 bytes
1136          dd if=boot/grub/core.img of="${ISO_OUTPUT}/${ISO_NAME}" \
1137            conv=notrunc bs=512 seek=4 2>/dev/null
1138       fi
1139
1140       # pad the output ISO to multiples of 256 KiB for partition table support
1141       siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1142       cyls=$((siz / 512 / 32 / 16 + 1))   # C=$cyls H=16 S=32
1143       siz=$((cyls * 16 * 32 * 512))   # size after padding
1144       dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1145          of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1146
1147       # support disabling hybrid ISO image
1148       if [ "$HYBRID_METHOD" = "disable" ] ; then\
1149          log   "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1150          einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1151          eend 0
1152       # use isohybrid only on request
1153       elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
1154          if ! which isohybrid >/dev/null 2>&1 ; then
1155            bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1156          else
1157            log "Creating hybrid ISO file with isohybrid method"
1158            einfo "Creating hybrid ISO file with isohybrid method"
1159            # Notes for consideration:
1160            # "-entry 4 -type 1c"
1161            # * using 4 as the partition number is supposed to help with BIOSes
1162            #   that only support USB-Zip boot
1163            # * using 1c (i.e. hidden FAT32 LBA), instead of the default 0x17
1164            #   (hidden NTFS, IIRC), as the partition type is sometimes needed
1165            #   to get the BIOS even look at the partition created by isohybrid
1166            isohybrid "${ISO_OUTPUT}/${ISO_NAME}"
1167            eend $?
1168          fi
1169       # by default use our manifold boot method:
1170       else
1171          # isoinfo is part of both mkisofs and genisoimage so we're good
1172          bootoff=$(isoinfo -l -i "${ISO_OUTPUT}/${ISO_NAME}" | \
1173            sed -n '/^.*\[ *\([0-9]*\)[] ].* ISOLINUX.BIN;1 *$/s//\1/p')
1174          if ! [ -r boot/grub/core.img ] ; then
1175            ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1176          elif [ "${bootoff:-0}" -lt 1 ] ; then
1177            ewarn "isolinux.bin not found on the ISO file, disabling manifold boot"
1178          else
1179            log "Creating hybrid ISO file with manifold method"
1180            einfo "Creating hybrid ISO file with manifold method"
1181            if [ "$HYBRID_METHOD" = "grub2" ] ; then
1182                # 512 bytes: MBR, partition table, load GRUB 2
1183                echo 4 63 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 4:0x96 -g $cyls:16:32
1184            else
1185               # read only one but 2048-byte sized (scale: << 2) sector
1186               echo $bootoff $bootoff | \
1187                  mksh /usr/share/grml-live/scripts/bootilnx.mksh -A -M 4:0x96 -g $cyls:16:32 -S 2
1188            fi | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1189            eend $?
1190          fi
1191       fi
1192
1193       # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1194       case $CLASSES in *RELEASE*)
1195          [ "$RC" = 0 ] && \
1196          (
1197            if cd $ISO_OUTPUT ; then
1198              md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1199              touch -r ${ISO_NAME} ${ISO_NAME}.md5
1200              sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1201              touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1202            fi
1203          )
1204          ;;
1205       esac
1206
1207       cd "$CURRENT_DIR"
1208    fi
1209
1210    if [ "$RC" = 0 ] ; then
1211       log   "Finished execution of stage 'iso build' [$(date)]"
1212       einfo "Finished execution of stage 'iso build'" ; eend 0
1213    else
1214       log    "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1215       eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1216       bailout $RC
1217    fi
1218 fi
1219 # }}}
1220
1221 # pack artifacts {{{
1222 if [ -n "$PACK_ARTIFACTS" ]; then
1223   log "Packing artifcats"
1224   einfo "Packing artifacts"
1225   [ -f "${CHROOT_ARCHIVE}" ] && rm -r "${CHROOT_ARCHIVE}"
1226   tar -c -a -f ${CHROOT_ARCHIVE} --preserve-permissions -C "$(dirname ${CHROOT_OUTPUT})" "$(basename ${CHROOT_OUTPUT})"
1227   eend 0
1228 fi
1229 # }}}
1230
1231 # log build information to database if grml-live-db is installed and enabled {{{
1232 dpkg_to_db() {
1233 if [ -d /usr/share/grml-live-db ] ; then
1234
1235   # safe defaults
1236   DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1237   [ -n "$DPKG_DATABASE" ]  || DPKG_DATABASE=/var/log/grml-live.db
1238   [ -n "$DPKG_DBSCRIPT" ]  || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1239   [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1240
1241   if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1242     log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1243     eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1244     bailout 14
1245   fi
1246
1247   # disable by default for now, not sure whether really everyone is using a local db file
1248   #if ! touch "$DPKG_DATABASE" ; then
1249   #  eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1250   #  bailout 14
1251   #fi
1252
1253   if ! [ -r "$DPKG_LIST" ] ; then
1254      log   "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1255      ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1256   else
1257      einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1258      log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1259      log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1260      eindent
1261
1262      if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1263        einfo "$DB_INFO"
1264        eend 0
1265      else
1266        eerror "$DB_INFO"
1267        eend 1
1268      fi
1269
1270      eoutdent
1271   fi
1272
1273 fi
1274 }
1275 # }}}
1276
1277 # finalize {{{
1278 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1279 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1280
1281 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1282
1283 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1284 bailout 0
1285 # }}}
1286
1287 ## END OF FILE #################################################################
1288 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2