Do not depend on /proc for calculating runtime
[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 # avoid leaking into chroots
16 unset TMPDIR
17
18 # define function getfilesize before "set -e"
19 if stat --help >/dev/null 2>&1; then
20   getfilesize='stat -c %s'  # GNU stat
21 else
22   getfilesize='stat -f %z'  # BSD stat
23 fi
24
25 # exit on any error:
26 # disable for now since it seems to cause some problems
27 # set -e
28
29 # The line following this line is patched by debian/rules.
30 GRML_LIVE_VERSION='***UNRELEASED***'
31
32 # global variables
33 PN="$(basename $0)"
34 CMDLINE="$0 $@"
35 ADDONS_LIST_FILE='/boot/isolinux/addons_list.cfg'
36 # }}}
37
38 # usage information {{{
39 usage()
40 {
41   echo "
42 $PN - build process script for generating a (grml based) Linux Live-ISO
43
44 Usage: $PN [options, see as follows]
45
46    -a <architecture>       architecture; available values: i386 and amd64
47    -A                      clean build directories before and after running
48    -b                      build the ISO without updating the chroot via FAI
49    -B                      build the ISO without touching the chroot (skips cleanup)
50    -c <classe[s]>          classes to be used for building the ISO via FAI
51    -C <configfile>         configuration file for grml-live
52    -d <date>               use specified date instead of build time as date of release
53    -D <configdir>          use specified configuration directory instead of /etc/grml/fai
54    -e <iso_name>           extract ISO and squashfs contents from iso_name
55    -F                      force execution without prompting
56    -g <grml_name>          set the grml flavour name
57    -h                      display short usage information and exit
58    -i <iso_name>           name of ISO
59    -I <src_directory>      directory which provides files that should become
60                            part of the chroot/ISO
61    -n                      skip generation of ISO
62    -N                      bootstrap (build chroot) only, do not create files for ISO
63    -o <output_directory>   main output directory of the build process
64    -q                      skip mksquashfs
65    -Q                      skip netboot package build
66    -r <release_name>       release name
67    -s <suite>              Debian suite/release, like: stable, testing, unstable
68    -S <script_directory>   place of scripts (defaults to /usr/share/grml-live/scripts)
69    -t <template_directory> place of the templates
70    -u                      update existing chroot instead of rebuilding it from scratch
71    -U <username>           arrange output to be owned by specified username
72    -v <version_number>     specify version number of the release
73    -V                      increase verbosity in the build process
74    -w <date>               wayback machine, build system using Debian archives
75                            from specified date
76    -z                      use ZLIB instead of LZMA/XZ compression
77
78 Usage examples:
79
80     $PN
81     $PN -c GRMLBASE,GRML_FULL,AMD64 -o /dev/shm/grml
82     $PN -c GRMLBASE,GRML_FULL,AMD64 -i grml_0.0-1.iso -v 0.0-1
83     $PN -c GRMLBASE,GRML_FULL,AMD64 -s stable -V -r 'grml-ftw'
84
85 More details: man grml-live + /usr/share/doc/grml-live/grml-live.html
86               http://grml.org/grml-live/
87
88 Please send your bug reports and feedback to the grml-team: http://grml.org/bugs/
89 "
90    [ "$(id -u 2>/dev/null)" != 0 ] && echo "Please notice that this script requires root permissions."
91 }
92
93 # make sure it's possible to get usage information without being
94 # root or actually executing the script
95 if [ "$1" = '-h' -o "$1" = '--help' ] ; then
96    usage
97    exit 0
98 fi
99 # }}}
100
101 # some runtime checks {{{
102 # we need root permissions for the build-process:
103 if [ "$(id -u 2>/dev/null)" != 0 ] ; then
104    echo "Error: please run this script with uid 0 (root)." >&2
105    exit 1
106 fi
107
108 if [ -r /var/run/fai/FAI_INSTALLATION_IN_PROGRESS ] ; then
109    echo "/usr/sbin/fai already running or was aborted before.">&2
110    echo "You may remove /var/run/fai/FAI_INSTALLATION_IN_PROGRESS and try again.">&2
111    exit 1
112 fi
113
114 # see #449236
115 if [ -r /var/run/fai/fai_softupdate_is_running ] ; then
116    echo "/usr/sbin/fai softupdate already running or was aborted before.">&2
117    echo "You may remove /var/run/fai/fai_softupdate_is_running and try again.">&2
118    exit 1
119 fi
120 # }}}
121
122 # lsb-functions and configuration stuff {{{
123 # make sure they are not set by default
124 VERBOSE=''
125 FORCE=''
126 UPDATE=''
127 BUILD_ONLY=''
128 BUILD_DIRTY=''
129 BOOTSTRAP_ONLY=''
130 HOSTNAME=''
131 USERNAME=''
132 CONFIGDUMP=''
133
134 # don't use colors/escape sequences
135 if [ -r /lib/lsb/init-functions ] ; then
136   . /lib/lsb/init-functions
137   ! log_use_fancy_output && NOCOLORS=true
138 fi
139
140 if [ -r /etc/grml/lsb-functions ] ; then
141    . /etc/grml/lsb-functions
142 else
143    einfo()  { echo "  [*] $*" ;}
144    eerror() { echo "  [!] $*">&2 ;}
145    ewarn()  { echo "  [x] $*" ;}
146    eend()   { return 0 ;}
147    eindent()  { return 0 ;}
148    eoutdent() { return 0 ;}
149 fi
150
151 # source main configuration file:
152 [ -z "$LIVE_CONF" ] && LIVE_CONF='/etc/grml/grml-live.conf'
153 if ! [ -r "$LIVE_CONF" ] ; then
154   ewarn "Configuration file $LIVE_CONF can not be read, ignoring"
155 else
156   einfo "Sourcing configuration file $LIVE_CONF"
157   . $LIVE_CONF
158   eend $?
159 fi
160 # }}}
161
162 # umount all directories {{{
163 umount_all() {
164    # make sure we don't leave any mounts - FAI doesn't remove them always
165    umount $CHROOT_OUTPUT/proc/sys/fs/binfmt_misc 2>/dev/null || /bin/true
166    umount $CHROOT_OUTPUT/proc 2>/dev/null || /bin/true
167    umount $CHROOT_OUTPUT/run/udev 2>/dev/null || /bin/true
168    umount $CHROOT_OUTPUT/run  2>/dev/null || /bin/true
169    umount $CHROOT_OUTPUT/sys  2>/dev/null || /bin/true
170    umount $CHROOT_OUTPUT/dev/pts 2>/dev/null || /bin/true
171    umount $CHROOT_OUTPUT/dev 2>/dev/null || /bin/true
172
173    if [ -n "$EXTRACT_ISO_NAME" ] ; then
174      umount "$EXTRACT_ISO_NAME" 2>/dev/null || /bin/true
175    fi
176
177    # certain FAI versions sadly leave a ramdisk behind, so better safe than sorry
178    if [ -x /usr/lib/fai/mkramdisk ] ; then
179      /usr/lib/fai/mkramdisk -u "$(readlink -f ${CHROOT_OUTPUT}/var/lib/dpkg)" >/dev/null 2>&1 || /bin/true
180    fi
181
182    umount "${CHROOT_OUTPUT}/grml-live/sources/" 2>/dev/null || /bin/true
183    [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
184 }
185 # }}}
186
187 # clean exit {{{
188 bailout() {
189   rm -f /var/run/fai/fai_softupdate_is_running \
190         /var/run/fai/FAI_INSTALLATION_IN_PROGRESS
191   [ -n "$CONFIGDUMP"      ]  && rm -f  "$CONFIGDUMP"
192   [ -n "$SQUASHFS_STDERR" ]  && rm -rf "$SQUASHFS_STDERR"
193   umount_all
194   [ -n "$1" ] && EXIT="$1" || EXIT="1"
195   [ -n "$2" ] && eerror "$2">&2
196   if [ -n "$CLEAN_ARTIFACTS" ]; then
197     log "Cleaning up"
198     einfo "Cleaning up"
199     [ -n "${BUILD_OUTPUT}"  -a -d "${BUILD_OUTPUT}"  ] && rm -r "${BUILD_OUTPUT}"
200     [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && rm -r "${CHROOT_OUTPUT}"
201     eend 0
202   fi
203
204   # get rid of automatically generated conffiles
205   rm -f ${GRML_FAI_CONFIG}/nfsroot.conf
206   rm -f ${GRML_FAI_CONFIG}/make-fai-nfsroot.conf
207
208   if [ -n "$CHOWN_USER" ]; then
209     log "Setting ownership"
210     einfo "Setting ownership"
211     [ -n "${OUTPUT}"         -a -d "${OUTPUT}"         ] && chown -R "${CHOWN_USER}:" "${OUTPUT}"
212     [ -n "${BUILD_OUTPUT}"   -a -d "${BUILD_OUTPUT}"   ] && chown -R "${CHOWN_USER}:" "${BUILD_OUTPUT}"
213     [ -n "${CHROOT_OUTPUT}"  -a -d "${CHROOT_OUTPUT}"  ] && chown -R "${CHOWN_USER}:" "${CHROOT_OUTPUT}"
214     [ -n "${ISO_OUTPUT}"     -a -d "${ISO_OUTPUT}"     ] && chown -R "${CHOWN_USER}:" "${ISO_OUTPUT}"
215     [ -n "${LOG_OUTPUT}"     -a -d "${LOG_OUTPUT}"     ] && chown -R "${CHOWN_USER}:" "${LOG_OUTPUT}"
216     [ -n "${NETBOOT}"        -a -d "${NETBOOT}"        ] && chown -R "${CHOWN_USER}:" "${NETBOOT}"
217     eend 0
218   fi
219   log "------------------------------------------------------------------------------"
220   exit "$EXIT"
221 }
222 trap bailout 1 2 3 3 6 9 14 15
223 trap umount_all EXIT
224 # }}}
225
226 # some important functions {{{
227
228 # log output:
229 # usage: log "string to log"
230 log() { [ -n "$LOGFILE" ] && echo "$*" >> $LOGFILE ; }
231
232 # cut string at character number int = $1
233 # usage: cut_string 5 "1234567890" will output "12345"
234 cut_string() {
235   [ -n "$2" ] || return 1
236   echo "$2" | head -c "$1"; echo -ne "\n"
237 }
238
239 # prepend int = $1 spaces before string = $2
240 # usage: extend_string_begin 5 "123" will output "  123"
241 extend_string_begin() {
242   [ -n "$2" ] || return 1
243   local COUNT="$(echo $2 | wc -c)"
244   local FILL="$(expr $COUNT - $1)"
245   while [ "$FILL" -gt 1 ] ; do
246     echo -n " "
247     local FILL=$(expr $FILL - 1)
248   done
249   while [ "$FILL" -lt 1 ] ; do
250     echo -n " "
251     local FILL=$(expr $FILL + 1)
252   done
253   echo "$2" | head -c "$1"; echo -ne "\n"
254 }
255
256 # append int = $1 spaces to string = $2
257 # usage: extend_string_begin 5 "123" will output "123  "
258 extend_string_end() {
259   [ -n "$2" ] || return 1
260   echo -n "$2" | head -c "$1"
261   local COUNT="$(echo $2 | wc -c)"
262   local FILL="$(expr $COUNT - $1)"
263   while [ "$FILL" -gt 1 ] ; do
264     echo -n " "
265     local FILL=$(expr $FILL - 1)
266   done
267   while [ "$FILL" -lt 1 ] ; do
268     echo -n " "
269     local FILL=$(expr $FILL + 1)
270   done
271   echo -ne "\n"
272 }
273
274 # Copy addonfile $1 from either
275 #   * the chroot (via $2, the system path),
276 #   * or from TEMPLATE_DIRECTORY/compat (if exists),
277 #   * or from the host system (again, using $2),
278 # or warn about the missing file.
279 #
280 # This is because:
281 #   * We assume that the chroot always has a "good" version of
282 #     the file. Also it makes sources handling easier.
283 #   * On unstable, we recommend the Debian packages containing
284 #     these files. The user can override them by putting his
285 #     "better" version into the chroot.
286 #   * With older releases the Debian packages are probably
287 #     not available, so we look in TEMPLATE_DIRECTORY/compat,
288 #     where a (custom) package might install current file versions.
289 copy_addon_file() {
290   DEST="${BUILD_OUTPUT}/boot/$3"
291   if [ ! -d "${DEST}/" ]; then
292     mkdir -p "${DEST}"
293   fi
294   if [ -e "$CHROOT_OUTPUT/$2/$1" ]; then
295     log   "Copying $1 from chroot"
296     cp "$CHROOT_OUTPUT/$2/$1" "${DEST}/"
297     return $?
298   fi
299   if [ -e "${TEMPLATE_DIRECTORY}/compat/$3/$1" ]; then
300     log   "Copying $1 from ${TEMPLATE_DIRECTORY}/compat"
301     cp "${TEMPLATE_DIRECTORY}/compat/$3/$1" "${DEST}/"
302     return $?
303   fi
304   if [ -e "$2/$1" ]; then
305     log   "Copying $1 from system"
306     cp "$2/$1" "${DEST}/"
307     return $?
308   fi
309
310   msg="Missing addon file: \"$1\""
311   ewarn "$msg" ; eend 1
312   log "copy_addon_file: $msg"
313 }
314
315 # replace placeholders in template files with actual information
316 adjust_boot_files() {
317   if [ -z "$1" ] ; then
318     echo "Usage: adjust_boot_files <template_file>" >&2
319     exit 1
320   fi
321
322   for file in "$@" ; do
323     if [ -r "${file}" ] && [ -f "${file}" ] ; then
324       sed -i "s/%ARCH%/$ARCH/g"                    "${file}"
325       sed -i "s/%DATE%/$DATE/g"                    "${file}"
326       sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g"      "${file}"
327       sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g"      "${file}"
328       sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g"  "${file}"
329       sed -i "s/%GRML_NAME%/$GRML_NAME/g"          "${file}"
330       sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g"  "${file}"
331       sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g"    "${file}"
332       sed -i "s/%SHORT_NAME%/$SHORT_NAME/g"        "${file}"
333       sed -i "s/%VERSION%/$VERSION/g"              "${file}"
334       if [ -n "${BOOT_FILE}" ] ; then
335         sed -i "s;%BOOT_FILE%;$BOOT_FILE;g"        "${file}"
336       fi
337
338       [ -n "$DEFAULT_BOOTOPTIONS" ] && sed -i "s; boot=live; boot=live $DEFAULT_BOOTOPTIONS;"  "${file}"
339
340       if [ -n "$NO_BOOTID" ] ; then
341         sed -i "s/ bootid=%BOOTID%//g" "${file}" # drop bootid bootoption
342       else
343         sed -i "s/%BOOTID%/$BOOTID/g" "${file}" # adjust bootid=... argument
344       fi
345     fi
346   done
347 }
348 # }}}
349
350 # command line parsing {{{
351 while getopts "a:C:c:d:D:e:g:i:I:o:r:s:S:t:U:v:w:AbBFhnNqQuVz" opt; do
352   case "$opt" in
353     a) ARCH="$OPTARG" ;;
354     A) CLEAN_ARTIFACTS=1 ;;
355     b) BUILD_ONLY=1 ;;
356     B) BUILD_DIRTY=1 ;;
357     c) CLASSES="$OPTARG" ;;
358     C) LOCAL_CONFIG="$(readlink -f $OPTARG)" ;;
359     d) DATE="$OPTARG" ;;
360     D) GRML_FAI_CONFIG="$(readlink -f $OPTARG)" ;;
361     e) EXTRACT_ISO_NAME="$(readlink -f $OPTARG)" ;;
362     g) GRML_NAME="$OPTARG" ;;
363     h) usage ; bailout 0 ;;
364     i) ISO_NAME="$OPTARG" ;;
365     I) CHROOT_INSTALL="$OPTARG" ;;
366     n) SKIP_MKISOFS=1 ;;
367     N) BOOTSTRAP_ONLY=1; SKIP_MKISOFS=1; SKIP_MKSQUASHFS=1 ;;
368     o) OUTPUT="$(readlink -f $OPTARG)" ;;
369     q) SKIP_MKSQUASHFS=1 ;;
370     Q) SKIP_NETBOOT=1 ;;
371     r) RELEASENAME="$OPTARG" ;;
372     s) SUITE="$OPTARG" ;;
373     S) SCRIPTS_DIRECTORY="$OPTARG";;
374     t) TEMPLATE_DIRECTORY="$OPTARG";;
375     v) VERSION="$OPTARG" ;;
376     F) FORCE=1 ;;
377     u) UPDATE=1 ;;
378     U) CHOWN_USER="$OPTARG" ;;
379     V) VERBOSE="-v" ;;
380     w) export WAYBACK_DATE="$OPTARG" ;;
381     z) SQUASHFS_ZLIB=1 ;;
382     ?) echo "invalid option -$OPTARG" >&2; usage; bailout 1 ;;
383   esac
384 done
385 shift $(($OPTIND - 1))  # set ARGV to the first not parsed commandline parameter
386
387 if [ -n "$1" ] ; then
388   echo "Error: unknown argument '$1' in options. Exiting to avoid possible data loss." >&2
389   bailout 1
390 fi
391 # }}}
392
393 # read local (non-packaged) configuration {{{
394 if [ -z "$LOCAL_CONFIG" ]; then
395   if [ -r "/etc/grml/grml-live.local" ]; then
396     LOCAL_CONFIG="/etc/grml/grml-live.local"
397   fi
398 fi
399 if [ -n "$LOCAL_CONFIG" ]; then
400   if [ -r "$LOCAL_CONFIG" ]; then
401     . $LOCAL_CONFIG
402   else
403     eerror "Could not read specified local configuration file \"$LOCAL_CONFIG\"."
404     bailout 1
405   fi
406   LOCAL_CONFIG=$(readlink -f "$LOCAL_CONFIG")
407 else
408   LOCAL_CONFIG=''
409 fi
410
411 if [ -n "${GRML_LIVE_SOURCES:-}" ] ; then
412   eerror "Config variable \$GRML_LIVE_SOURCES is set. This variable has been deprecated."
413   ewarn  "Please set up \${GRML_FAI_CONFIG}/config/files/etc/apt/sources.list.d/* instead."
414   bailout 1
415 fi
416 # }}}
417
418 # assume sane defaults (if not set already) {{{
419 [ -n "$ARCH" ]                    || ARCH="$(dpkg --print-architecture)"
420 [ -n "$BOOT_METHOD" ]             || BOOT_METHOD='isolinux'
421 [ -n "$CLASSES" ]                 || CLASSES="GRMLBASE,GRML_FULL,$(echo ${ARCH} | tr 'a-z' 'A-Z')"
422 [ -n "$DATE" ]                    || DATE="$(date +%Y-%m-%d)"
423 [ -n "$DISTRI_INFO" ]             || DISTRI_INFO='Grml - Live Linux for system administrators'
424 [ -n "$DISTRI_NAME" ]             || DISTRI_NAME="grml"
425 [ -n "$DISTRI_SPLASH" ]           || DISTRI_SPLASH='grml.png'
426 [ -n "$FORCE_ISO_REBUILD" ]       || FORCE_ISO_REBUILD="false"
427 [ -n "$GRML_FAI_CONFIG" ]         || GRML_FAI_CONFIG='/etc/grml/fai'
428 [ -n "$GRML_NAME" ]               || GRML_NAME='grml'
429 [ -n "$HOSTNAME" ]                || HOSTNAME='grml'
430 [ -n "$HYBRID_METHOD" ]           || HYBRID_METHOD='isohybrid'
431 [ -n "$RELEASENAME" ]             || RELEASENAME='grml-live rocks'
432 [ -n "$SECURE_BOOT" ]             || SECURE_BOOT='disable'
433 [ -n "$SQUASHFS_EXCLUDES_FILE" ]  || SQUASHFS_EXCLUDES_FILE="${GRML_FAI_CONFIG}/config/grml/squashfs-excludes"
434 [ -n "$SUITE" ]                   || SUITE='testing'
435 [ -n "$TEMPLATE_DIRECTORY" ]      || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
436 [ -n "$SCRIPTS_DIRECTORY" ]       || SCRIPTS_DIRECTORY='/usr/share/grml-live/scripts'
437 [ -n "$USERNAME" ]                || USERNAME='grml'
438 [ -n "$VERSION" ]                 || VERSION='0.0.1'
439
440 # output specific stuff, depends on $OUTPUT (iff not set):
441 [ -n "$OUTPUT" ]           || OUTPUT="$PWD/grml/"
442 [ -n "$BUILD_OUTPUT" ]     || BUILD_OUTPUT="$OUTPUT/grml_cd"
443 [ -n "$CHROOT_OUTPUT" ]    || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
444 [ -n "$ISO_OUTPUT" ]       || ISO_OUTPUT="$OUTPUT/grml_isos"
445 [ -n "$LOG_OUTPUT" ]       || LOG_OUTPUT="$OUTPUT/grml_logs"
446 [ -n "$REPORTS" ]          || REPORTS="${LOG_OUTPUT}/reports/"
447 [ -n "$NETBOOT" ]          || NETBOOT="${OUTPUT}/netboot/"
448 # }}}
449
450 # some misc checks before executing FAI {{{
451 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
452 specify it on the command line using the -c option."
453 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
454 specify it on the command line using the -o option."
455
456 # trim characters that are known to cause problems inside $GRML_NAME;
457 # for example isolinux does not like '-' inside the directory name
458 [ -n "$GRML_NAME" ] && export SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
459
460 # export variables to have them available in fai scripts:
461 [ -n "$GRML_NAME" ]   && export GRML_NAME="$GRML_NAME"
462 [ -n "$RELEASENAME" ] && export RELEASENAME="$RELEASENAME"
463 # }}}
464
465 # ZERO_LOGFILE - check for backwards compatibility reasons {{{
466 # this was default behaviour until grml-live 0.9.34:
467 if [ -n "$ZERO_LOGFILE" ] ; then
468    PRESERVE_LOGFILE='' # make sure it's cleaned then
469    ewarn "Please consider disabling the \$ZERO_LOGFILE option as grml-live clears..."
470    ewarn "... the logfile $LOGFILE by default (unless \$PRESERVE_LOGFILE is set) nowadays."
471    eend 0
472 fi
473 # }}}
474
475 # ask user whether the setup is ok {{{
476 if [ -z "$FORCE" ] ; then
477    echo
478    echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
479    echo
480    echo "  FAI classes:       $CLASSES"
481    [ -n "$LOCAL_CONFIG" ]        && echo "  Configuration:     $LOCAL_CONFIG"
482    [ -n "$GRML_FAI_CONFIG" ]     && echo "  Config directory:  $GRML_FAI_CONFIG"
483    echo "  main directory:    $OUTPUT"
484    [ -n "$EXTRACT_ISO_NAME" ]    && echo "  Extract ISO:       $EXTRACT_ISO_NAME"
485    [ -n "$CHROOT_OUTPUT" ]       && echo "  Chroot target:     $CHROOT_OUTPUT"
486    [ -n "$BUILD_OUTPUT" ]        && echo "  Build target:      $BUILD_OUTPUT"
487    [ -n "$ISO_OUTPUT" ]          && echo "  ISO target:        $ISO_OUTPUT"
488    [ -n "$GRML_NAME" ]           && echo "  Grml name:         $GRML_NAME"
489    [ -n "$RELEASENAME" ]         && echo "  Release name:      $RELEASENAME"
490    [ -n "$DATE" ]                && echo "  Build date:        $DATE"
491    [ -n "$VERSION" ]             && echo "  Grml version:      $VERSION"
492    [ -n "$SUITE" ]               && echo "  Debian suite:      $SUITE"
493    [ -n "$ARCH" ]                && echo "  Architecture:      $ARCH"
494    [ -n "$BOOT_METHOD" ]         && echo "  Boot method:       $BOOT_METHOD"
495    [ -n "$HYBRID_METHOD" ]       && echo "  Hybrid method:     $HYBRID_METHOD"
496    [ -n "$TEMPLATE_DIRECTORY" ]  && echo "  Template files:    $TEMPLATE_DIRECTORY"
497    [ -n "$CHROOT_INSTALL" ]      && echo "  Install files from directory to chroot:  $CHROOT_INSTALL"
498    [ -n "$BOOTID" ]              && echo "  Boot identifier:   $BOOTID"
499    [ -n "$NO_BOOTID" ]           && echo "  Skipping bootid feature."
500    [ -n "$CHOWN_USER" ]          && echo "  Output owner:      $CHOWN_USER"
501    [ -n "$DEFAULT_BOOTOPTIONS" ] && echo "  Adding default bootoptions: \"$DEFAULT_BOOTOPTIONS\""
502    [ -n "$FAI_ARGS" ]            && echo "  Additional arguments for FAI: $FAI_ARGS"
503    [ -n "$LOGFILE" ]             && echo "  Logging to file:   $LOGFILE"
504    [ -n "$SQUASHFS_ZLIB" ]       && echo "  Using ZLIB (instead of LZMA/XZ) compression."
505    [ -n "$SQUASHFS_OPTIONS" ]    && echo "  Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
506    [ -n "$VERBOSE" ]             && echo "  Using VERBOSE mode."
507    [ -n "$CLEAN_ARTIFACTS" ]     && echo "  Will clean output before and after running."
508    [ -n "$UPDATE" ]              && echo "  Executing UPDATE instead of fresh installation."
509    if [ -n "$BOOTSTRAP_ONLY" ] ; then
510      echo "  Bootstrapping only and not building (files for) ISO."
511    else
512      [ -n "$SKIP_MKSQUASHFS" ]     && echo "  Skipping creation of SQUASHFS file."
513      [ -n "$SKIP_NETBOOT" ]        && echo "  Skipping creation of NETBOOT package."
514      [ -n "$SKIP_MKISOFS" ]        && echo "  Skipping creation of ISO file."
515      [ -n "$BUILD_ONLY" ]          && echo "  Executing BUILD_ONLY instead of fresh installation or UPDATE."
516      [ -n "$BUILD_DIRTY" ]         && echo "  Executing BUILD_DIRTY to leave chroot untouched."
517    fi
518    echo
519    echo -n "Is this ok for you? [y/N] "
520    read a
521    if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
522       CLEAN_ARTIFACTS=0
523       echo "Exiting as requested."
524       exit 0
525    fi
526    echo
527 fi
528 # }}}
529
530 # clean up before start {{{
531 if [ -n "${CLEAN_ARTIFACTS}" ]; then
532   echo "Wiping old artifacts"
533   [ -n "${CHROOT_OUTPUT}"  -a -d "${CHROOT_OUTPUT}"  ] && rm -r "${CHROOT_OUTPUT}"
534   [ -n "${BUILD_OUTPUT}"   -a -d "${BUILD_OUTPUT}"   ] && rm -r "${BUILD_OUTPUT}"
535   [ -n "${ISO_OUTPUT}"     -a -d "${ISO_OUTPUT}"     ] && rm -r "${ISO_OUTPUT}"
536   [ -n "${LOG_OUTPUT}"     -a -d "${LOG_OUTPUT}"     ] && rm -r "${LOG_OUTPUT}"
537   [ -n "${NETBOOT}"        -a -d "${NETBOOT}"        ] && rm -r "${NETBOOT}"
538 fi
539 # }}}
540
541 # create log file {{{
542 [ -n "$LOGFILE" ] || LOGFILE=${LOG_OUTPUT}/grml-live.log
543 mkdir -p $(dirname "${LOGFILE}")
544 touch $LOGFILE
545 chown root:adm $LOGFILE
546 chmod 664 $LOGFILE
547 # }}}
548
549 # clean/zero/remove logfiles {{{
550
551 if [ -n "$PRESERVE_LOGFILE" ] ; then
552    echo "Preserving logfile $LOGFILE as requested via \$PRESERVE_LOGFILE"
553 else
554    # make sure it is empty (as it is e.g. appended to grml-live-db)
555    echo -n > $LOGFILE
556 fi
557
558 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
559    if [ -d /var/log/fai/"$HOSTNAME" ] ; then
560       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
561       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
562       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
563       rm -f /var/log/fai/"$HOSTNAME"/last \
564             /var/log/fai/"$HOSTNAME"/last-dirinstall \
565             /var/log/fai/"$HOSTNAME"/last-softupdate
566    fi
567 fi
568 # }}}
569
570 # source config and startup {{{
571 if [ -n "$CONFIG" ] ; then
572    if ! [ -f "$CONFIG" ] ; then
573       log    "Error: $CONFIG could not be read. Exiting. [$(date)]"
574       eerror "Error: $CONFIG could not be read. Exiting." ; eend 1
575       bailout 1
576    else
577       log "Sourcing $CONFIG"
578       . $CONFIG
579    fi
580 fi
581
582 SECONDS=unknown
583 start_seconds="$(date +%s)"
584 log "------------------------------------------------------------------------------"
585 log "Starting grml-live [${GRML_LIVE_VERSION}] run on $(date)"
586 log "Using local config file: $LOCAL_CONFIG"
587 log "Executed grml-live command line:"
588 log "$CMDLINE"
589
590 einfo "Logging actions to logfile $LOGFILE"
591 # }}}
592
593 # dump config variables into file, for script access {{{
594 CONFIGDUMP=$(mktemp)
595 set | egrep \
596   '^(GRML_NAME|RELEASENAME|DATE|VERSION|SUITE|ARCH|DISTRI_NAME|USERNAME|HOSTNAME|APT_PROXY)=' \
597   > ${CONFIGDUMP}
598 # }}}
599
600 # unpack iso/squashfs {{{
601 extract_iso() {
602 if [ -n "$EXTRACT_ISO_NAME" ]; then
603   log "Unpacking ISO from ${EXTRACT_ISO_NAME}"
604   einfo "Unpacking ISO from ${EXTRACT_ISO_NAME}"
605   local mountpoint=$(mktemp -d)
606   local rc=0
607   mount -o loop "${EXTRACT_ISO_NAME}" "$mountpoint" ; rc=$?
608   if [ "$rc" != 0 ]; then
609     rmdir "$mountpoint"
610     log "mount failed"
611     eerror "mount failed"
612     eend 1
613     bailout 1
614   fi
615
616   if ls "${mountpoint}"/live/*/*.squashfs 2>/dev/null | grep -q . ; then # ISOs >=2011.12
617     log "Using ${mountpoint}/live/*/*.squashfs for unsquashfs"
618     unsquashfs -d "${CHROOT_OUTPUT}" "${mountpoint}"/live/*/*.squashfs ; rc=$?
619   elif ls "${mountpoint}"/live/*.squashfs 2>/dev/null | grep -q . ; then # ISOs before 2011.12
620     log "Using ${mountpoint}/live/*.squashfs for unsquashfs"
621     unsquashfs -d "${CHROOT_OUTPUT}" "${mountpoint}"/live/*.squashfs ; rc=$?
622   else
623     log "Error: Could not find any *.squashfs files on the ISO"
624     eerror "Error: Could not find any *.squashfs files on the ISO"
625     eend 1
626     bailout 1
627   fi
628
629   umount "$mountpoint"
630   rmdir "$mountpoint"
631   if [ "$rc" != 0 ]; then
632     log "unsquashfs failed"
633     eerror "unsquashfs failed"
634     eend 1
635     bailout 1
636   fi
637 fi
638 }
639 extract_iso
640 # }}}
641
642 # on-the-fly configuration {{{
643
644 # does this suck? YES!
645 # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
646 case $SUITE in
647    unstable) SUITE='sid' ; CLASSES="DEBIAN_UNSTABLE,$CLASSES" ;;
648    *) CLASSES="DEBIAN_$(echo $SUITE | tr 'a-z' 'A-Z'),$CLASSES";;
649 esac
650 export SUITE # make sure it's available in FAI scripts
651
652 # validate whether the specified architecture class matches the
653 # architecture (option), otherwise installation of kernel will fail
654 if echo $CLASSES | grep -qw I386 ; then
655    if ! [[ "$ARCH" == "i386" ]] ; then
656       log    "Error: You specified the I386 class but are trying to build something else (AMD64?)."
657       eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
658       eerror "Tip:   Either invoke grml-live with '-a i386' or adjust the architecture class. Exiting."
659       eend 1
660       bailout
661    fi
662 elif echo $CLASSES | grep -qi amd64 ; then
663    if ! [[ "$ARCH" == "amd64" ]] ; then
664       log    "Error: You specified the AMD64 class but are trying to build something else (I386?)."
665       eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
666       eerror "Tip:   Either invoke grml-live with '-a amd64' or adjust the architecture class. Exiting."
667       eend 1
668       bailout
669    fi
670 fi
671
672 # generate nfsroot configuration for FAI on the fly
673 if [ -z "$FAI_DEBOOTSTRAP" ] ; then
674   if [ -n "$WAYBACK_DATE" ] ; then
675     FAI_DEBOOTSTRAP="$SUITE http://snapshot.debian.org/archive/debian/$WAYBACK_DATE/"
676   else
677     FAI_DEBOOTSTRAP="$SUITE http://ftp.debian.org/debian"
678   fi
679 fi
680
681 if [ -z "$FAI_DEBOOTSTRAP_OPTS" ] ; then
682   FAI_DEBOOTSTRAP_OPTS="--exclude=info,tasksel,tasksel-data --include=aptitude --arch $ARCH --no-merged-usr"
683 fi
684
685 # create backup of old (not yet automatically generated) config file
686 if [ -f "${GRML_FAI_CONFIG}/make-fai-nfsroot.conf" ] ; then
687   if ! grep -q 'This is an automatically generated file by grml-live' "${GRML_FAI_CONFIG}/make-fai-nfsroot.conf" ; then
688     ewarn "Found old ${GRML_FAI_CONFIG}/make-fai-nfsroot.conf - moving to ${GRML_FAI_CONFIG}/make-fai-nfsroot.conf.outdated"
689     mv "${GRML_FAI_CONFIG}/make-fai-nfsroot.conf" "${GRML_FAI_CONFIG}/make-fai-nfsroot.conf.outdated"
690     eend $?
691   fi
692 fi
693
694 echo "# This is an automatically generated file by grml-live.
695 # Do NOT edit this file, your changes will be lost.
696 FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"
697 FAI_DEBOOTSTRAP_OPTS=\"$FAI_DEBOOTSTRAP_OPTS\"
698 # EOF " > "${GRML_FAI_CONFIG}/nfsroot.conf"
699 # support FAI <=3.4.8, versions >=4.0 use nfsroot.conf
700 ( cd ${GRML_FAI_CONFIG} && ln -sf nfsroot.conf make-fai-nfsroot.conf )
701 # }}}
702
703 # CHROOT_OUTPUT - execute FAI {{{
704 if [ -n "$BUILD_DIRTY" ]; then
705    log   "Skipping stage 'fai' as requested via option -B"
706    ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
707 else
708    [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
709
710    if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
711       FAI_ACTION=softupdate
712    else
713       FAI_ACTION=dirinstall
714    fi
715
716    if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
717       if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
718          log    "Error: does not look like you have a working chroot. Updating/building not possible."
719          eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
720          eend 1
721          bailout 20
722       fi
723    fi
724
725    if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
726       log   "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
727       ewarn "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
728    else
729       mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
730
731       if [ -n "${MIRROR_DIRECTORY}" ] ; then
732          mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
733          mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
734       fi
735
736       mkdir -p "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
737       mount --bind "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
738
739       log "Executed FAI command line:"
740       log "BUILD_ONLY=$BUILD_ONLY BOOTSTRAP_ONLY=$BOOTSTRAP_ONLY GRML_LIVE_CONFIG=$CONFIGDUMP WAYBACK_DATE=$WAYBACK_DATE fai $VERBOSE -C $GRML_FAI_CONFIG -s file:///$GRML_FAI_CONFIG/config -c$CLASSES -u $HOSTNAME $FAI_ACTION $CHROOT_OUTPUT $FAI_ARGS"
741       BUILD_ONLY="$BUILD_ONLY" BOOTSTRAP_ONLY="$BOOTSTRAP_ONLY" GRML_LIVE_CONFIG="$CONFIGDUMP" fai $VERBOSE \
742                   -C "$GRML_FAI_CONFIG" -s "file:///$GRML_FAI_CONFIG/config" -c"$CLASSES" \
743                   -u "$HOSTNAME" "$FAI_ACTION" "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
744       RC="$PIPESTATUS" # notice: bash-only
745
746       if [ "$RC" != 0 ] ; then
747          log    "Error: critical error while executing fai [exit code ${RC}]. Exiting."
748          eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
749          bailout 1
750       fi
751
752       # provide inform fai about the ISO we build, needs to be provided
753       # *after* FAI stage, otherwise FAI skips the debootstrap stage if
754       # there is not BASEFILE (as it checks for presence of /etc) :(
755       echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
756       [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
757       [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
758
759       FORCE_ISO_REBUILD=true
760
761       # move fai logs into grml_logs directory
762       mkdir -p "$LOG_OUTPUT"/fai/
763       cp -r "$CHROOT_OUTPUT"/var/log/fai/"$HOSTNAME"/last/* "$LOG_OUTPUT"/fai/
764       rm -rf "$CHROOT_OUTPUT"/var/log/fai
765
766       # store copy of autogenerated configuration file
767       cp ${GRML_FAI_CONFIG}/nfsroot.conf "$LOG_OUTPUT"/fai/
768
769       # copy fai package list
770       cp "$CHROOT_OUTPUT"/var/log/install_packages.list "$LOG_OUTPUT"/fai/
771       # fixup owners
772       chown root:adm "$LOG_OUTPUT"/fai/*
773       chmod 664 "$LOG_OUTPUT"/fai/*
774
775       umount_all
776
777       # notice: 'fai dirinstall' does not seem to exit appropriate, so:
778       ERROR=''
779       CHECKLOG="$LOG_OUTPUT"/fai/
780       if [ -r "$CHECKLOG/software.log" ] ; then
781          # 1 errors during executing of commands
782          grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
783          grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
784          grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
785          grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
786          grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
787       fi
788
789       if [ -r "$CHECKLOG/shell.log" ] ; then
790          grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=6
791       fi
792
793       if [ -r "$CHECKLOG/fai.log" ] ; then
794         grep 'updatebase.*FAILED with exit code' "$CHECKLOG/fai.log" >> "$LOGFILE" && ERROR=7
795         grep 'instsoft.*FAILED with exit code'   "$CHECKLOG/fai.log" >> "$LOGFILE" && ERROR=8
796       fi
797
798       if [ -n "$ERROR" ] ; then
799          log    "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
800          eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
801          eerror "Note:  check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
802          eend 1
803          bailout 1
804       else
805          log "Finished execution of stage 'fai dirinstall' [$(date)]"
806          einfo "Finished execution of stage 'fai dirinstall'"
807       fi
808    fi
809 fi # BUILD_DIRTY?
810 # }}}
811
812 # package validator {{{
813 CHECKLOG=/var/log/fai/$HOSTNAME/last
814 if [ -r "$CHECKLOG/dpkg.selections" ] ; then
815   package_count=$(wc -l "$CHECKLOG/dpkg.selections" | awk '{print $1}')
816 else
817   package_count="unknown"
818 fi
819
820 mkdir -p "$REPORTS"
821 REPORT_MISSING_PACKAGES="${REPORTS}/TEST-MissingPackages.xml"
822
823 # check for missing packages
824 if ! [ -s "$CHECKLOG/package_errors.log" ] ; then
825   einfo "No missing packages found, generating empty junit report."
826
827   cat > "${REPORT_MISSING_PACKAGES}" << EOF
828 <?xml version="1.0" encoding="UTF-8"?>
829 <testsuite name="grml-live-missing-packages" tests="${package_count}" time="1" failures="0" errors="0" skipped="0" assertions="0">
830   <testcase name="test_missing_packages" time="0" assertions="0">
831   </testcase>
832   <system-out>
833   </system-out>
834   <system-err>
835   </system-err>
836 </testsuite>
837 EOF
838   eend 0
839 else
840   einfo "Missing packages found, generating junit report."
841
842   if [ -r "$CHECKLOG/package_errors.log" ] ; then
843     package_errors=$(wc -l "$CHECKLOG/package_errors.log" | awk '{print $1}')
844   else
845     package_errors="unknown"
846   fi
847
848   mkdir -p "$REPORTS"
849   REPORT_MISSING_PACKAGES="${REPORTS}/TEST-MissingPackages.xml"
850
851   cat > "${REPORT_MISSING_PACKAGES}" << EOF
852 <?xml version="1.0" encoding="UTF-8"?>
853 <testsuite name="grml-live-missing-packages" tests="${package_count}" time="1" failures="${package_errors}" errors="${package_errors}" skipped="0" assertions="0">
854 EOF
855
856   for package in $(awk '{print $1}' "${CHECKLOG}/package_errors.log" | sed 's;/;\\/;') ; do
857     failure_reason="$(awk "/$package/ {print \$2}" "${CHECKLOG}/package_errors.log")"
858     cat >> "${REPORT_MISSING_PACKAGES}" << EOF
859   <testcase name="test_missing_packages_${package}" time="0" assertions="0">
860     <failure type="${failure_reason}" message="Package ${package} is missing">
861 Package $package is missing in chroot (${failure_reason})
862   </failure>
863   </testcase>
864 EOF
865   done
866
867   cat >> "${REPORT_MISSING_PACKAGES}" << EOF
868   <system-out>
869   </system-out>
870   <system-err>
871   </system-err>
872 </testsuite>
873 EOF
874   eend 0
875
876   if [ -n "$EXIT_ON_MISSING_PACKAGES" -a -z "$BUILD_DIRTY" ] ; then
877     eerror "The following packages were requested for installation but could not be processed:"
878     cat "$CHECKLOG/package_errors.log"
879     eerror "... exiting as requested via \$EXIT_ON_MISSING_PACKAGES."
880     eend 1
881     bailout 13
882   else
883     ewarn "The following packages were requested for installation but could not be processed:"
884     cat "$CHECKLOG/package_errors.log"
885     eend 0
886   fi
887 fi
888 # }}}
889
890 # grub boot {{{
891 grub_setup() {
892   BOOTX64="/boot/bootx64.efi"
893   BOOTX32="/boot/bootia32.efi"
894   EFI_IMG="/boot/efi.img"
895
896   if [[ "$ARCH" == "amd64" ]] ; then
897     # important: this depends on execution of ${GRML_FAI_CONFIG}/config/scripts/GRMLBASE/45-grub-images
898     if ! [ -r "${CHROOT_OUTPUT}/${BOOTX64}" ] ; then
899       log    "Can not access GRUB efi image ${CHROOT_OUTPUT}/${BOOTX64}, required for Secure Boot support"
900       eerror "Can not access GRUB efi image ${CHROOT_OUTPUT}/${BOOTX64}, required for Secure Boot support" ; eend 1
901       log    "Possible reason is failure to run ${GRML_FAI_CONFIG}/config/scripts/GRMLBASE/45-grub-images"
902       ewarn  "Possible reason is failure to run ${GRML_FAI_CONFIG}/config/scripts/GRMLBASE/45-grub-images"
903       bailout 50
904     fi
905
906     dd if=/dev/zero of="${CHROOT_OUTPUT}/${EFI_IMG}" bs=4M count=1 2>/dev/null || bailout 50
907     mkfs.vfat -n GRML "${CHROOT_OUTPUT}/${EFI_IMG}" >/dev/null || bailout 51
908     mmd -i "${CHROOT_OUTPUT}/${EFI_IMG}" ::EFI || bailout 52
909     mmd -i "${CHROOT_OUTPUT}/${EFI_IMG}" ::EFI/BOOT || bailout 52
910
911     if [ "${SECURE_BOOT:-}" = "disable" ] ; then
912       log   "Secure Boot is disabled."
913       einfo "Secure Boot is disabled." ; eend 0
914
915       # install "$BOOTX64" as ::EFI/BOOT/bootx64.efi inside image file "$EFI_IMG":
916       mcopy -i "${CHROOT_OUTPUT}/${EFI_IMG}" "${CHROOT_OUTPUT}/${BOOTX64}" ::EFI/BOOT/bootx64.efi >/dev/null || bailout 53
917
918       log   "Generated 64-bit EFI image $BOOTX64"
919       einfo "Generated 64-bit EFI image $BOOTX64" ; eend 0
920     else
921       log   "Secure Boot is enabled [mode: $SECURE_BOOT]"
922       einfo "Secure Boot is enabled [mode: $SECURE_BOOT]" ; eend 0
923
924       if [ "${SECURE_BOOT}" = "ubuntu" ] ; then
925         local GRUBCFG_TEMPLATE="${TEMPLATE_DIRECTORY}/secureboot/grub.cfg"
926         local GRUBCFG_TMP=$(mktemp)
927
928         if ! [ -r "${GRUBCFG_TEMPLATE}" ] ; then
929           log    "Secure Boot template for GRUB [${GRUBCFG_TEMPLATE}] not found."
930           eerror "Secure Boot template for GRUB [${GRUBCFG_TEMPLATE}] not found." ; eend 1
931           bailout 54
932         fi
933
934         cp "${GRUBCFG_TEMPLATE}" "${GRUBCFG_TMP}"
935         adjust_boot_files "${GRUBCFG_TMP}"
936
937         mmd -i "${CHROOT_OUTPUT}/${EFI_IMG}" ::EFI/ubuntu || bailout 55
938         mcopy -i "${CHROOT_OUTPUT}/${EFI_IMG}" "${GRUBCFG_TMP}" ::EFI/ubuntu/grub.cfg || bailout 56
939         rm "${GRUBCFG_TMP}"
940
941         mcopy -i "${CHROOT_OUTPUT}/${EFI_IMG}" "${TEMPLATE_DIRECTORY}"/EFI/BOOT/grubx64.efi.signed ::EFI/BOOT/grubx64.efi >/dev/null || bailout 57
942         mcopy -i "${CHROOT_OUTPUT}/${EFI_IMG}" "${TEMPLATE_DIRECTORY}"/EFI/BOOT/shimx64.efi.signed ::EFI/BOOT/bootx64.efi >/dev/null || bailout 58
943
944         log   "Generated 64-bit Secure Boot (ubuntu) EFI image ${CHROOT_OUTPUT}/${EFI_IMG}"
945         einfo "Generated 64-bit Secure Boot (ubuntu) EFI image ${CHROOT_OUTPUT}/${EFI_IMG}" ; eend 0
946       fi
947     fi
948   fi
949
950   if [[ "$ARCH" == "i386" ]] ; then
951     if ! [ -r "${CHROOT_OUTPUT}/${BOOTX32}" ] ; then
952       log    "Can not access GRUB efi image ${CHROOT_OUTPUT}/${BOOTX32}."
953       eerror "Can not access GRUB efi image ${CHROOT_OUTPUT}/${BOOTX32}." ; eend 1
954       log    "Possible reason is failure to run ${GRML_FAI_CONFIG}/config/scripts/GRMLBASE/45-grub-images"
955       ewarn "Possible reason is failure to run ${GRML_FAI_CONFIG}/config/scripts/GRMLBASE/45-grub-images"
956       bailout 50
957     fi
958
959     dd if=/dev/zero of="${CHROOT_OUTPUT}/${EFI_IMG}" bs=4M count=1 2>/dev/null || bailout 50
960     mkfs.vfat -n GRML "${CHROOT_OUTPUT}/${EFI_IMG}" >/dev/null || bailout 51
961     mmd -i "${CHROOT_OUTPUT}/${EFI_IMG}" ::EFI || bailout 52
962     mmd -i "${CHROOT_OUTPUT}/${EFI_IMG}" ::EFI/BOOT || bailout 52
963     mcopy -i "${CHROOT_OUTPUT}/${EFI_IMG}" "${CHROOT_OUTPUT}/${BOOTX32}" ::EFI/BOOT/bootia32.efi >/dev/null || bailout 53
964     log   "Generated 32-bit EFI image $BOOTX32"
965     einfo "Generated 32-bit EFI image $BOOTX32" ; eend 0
966   fi
967 }
968 # }}}
969
970 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
971 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
972 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
973
974 # prepare ISO
975 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
976   if [ -n "$BOOTSTRAP_ONLY" ] ; then
977     log   "Skipping stage 'boot' as building with bootstrap only."
978     ewarn "Skipping stage 'boot' as building with bootstrap only." ; eend 0
979   else
980     # booting stuff:
981     mkdir -p "$BUILD_OUTPUT"/boot/isolinux
982     mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
983
984     # if we don't have an initrd we a) can't boot and b) there was an error
985     # during build, so check for the file:
986     INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
987     if [ -n "$INITRD" ] ; then
988       cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.img
989       find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
990     else
991       log    "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
992       eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
993       bailout 10
994     fi
995
996     KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
997     if [ -n "$KERNEL_IMAGE" ] ; then
998       cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/vmlinuz
999     else
1000       log    "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
1001       eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
1002       bailout 11
1003     fi
1004
1005     # we need to set "$BOOTID" before we invoke adjust_boot_files for the
1006     # first time, being inside grub_setup below
1007     if [ -n "$NO_BOOTID" ] ; then
1008       log   'Skipping bootid feature as requested via $NO_BOOTID.'
1009       einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
1010     else
1011       [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
1012       mkdir -p "$BUILD_OUTPUT"/conf
1013       einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
1014       log   "Generating /conf/bootid.txt with entry ${BOOTID}."
1015       echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
1016       eend $?
1017     fi
1018
1019     # every recent Grml ISO ships a /conf/bootid.txt, though GRUB might find
1020     # the /conf/bootid.txt of a different (Grml) ISO than the one that's
1021     # supposed to be running, so within scripts/GRMLBASE/45-grub-images
1022     # we generate a random filename, stored inside /boot/grub/bootfile.txt,
1023     # which we place on the resulting ISO here
1024     if [ -r "${CHROOT_OUTPUT}"/boot/grub/bootfile.txt ] ; then
1025       mkdir -p "${BUILD_OUTPUT}"/conf
1026       rm -f "${BUILD_OUTPUT}"/conf/bootfile*  # ensure we don't leave any old(er) files behind
1027
1028       einfo "Generating "${BUILD_OUTPUT}"/conf/bootfile* files"
1029       log   "Generating "${BUILD_OUTPUT}"/conf/bootfile* files"
1030
1031       BOOT_FILE="/conf/bootfile_$(cat "${CHROOT_OUTPUT}"/boot/grub/bootfile.txt)"
1032       echo "# This file is relevant for GRUB boot with the Grml ISO." > "${BUILD_OUTPUT}/${BOOT_FILE}"
1033       # save information about the random filename inside /conf/bootfile.txt
1034       echo "${BOOT_FILE}" > "${BUILD_OUTPUT}"/conf/bootfile.txt
1035       eend $?
1036     fi
1037
1038     grub_setup
1039
1040     # EFI boot files
1041     if [ -r "${CHROOT_OUTPUT}/boot/efi.img" -a -r "${CHROOT_OUTPUT}/boot/bootx64.efi" ] ; then
1042       einfo "Copying 64-bit EFI boot files into ISO path."
1043       log   "Copying 64-bit EFI boot files into ISO path."
1044       RC=$0
1045       cp "${CHROOT_OUTPUT}/boot/efi.img" "${BUILD_OUTPUT}/boot/" || RC=$?
1046       mkdir -p "${BUILD_OUTPUT}/EFI/BOOT/" || RC=$?
1047       cp "${CHROOT_OUTPUT}/boot/bootx64.efi" "${BUILD_OUTPUT}/EFI/BOOT/bootx64.efi" || RC=$?
1048       eend $?
1049     elif [ -r "${CHROOT_OUTPUT}/boot/efi.img" -a -r "${CHROOT_OUTPUT}/boot/bootia32.efi" ] ; then
1050       einfo "Copying 32-bit EFI boot files into ISO path."
1051       log "Copying 32-bit EFI boot files into ISO path."
1052       RC=$0
1053       cp "${CHROOT_OUTPUT}/boot/efi.img" "${BUILD_OUTPUT}/boot/" || RC=$?
1054       mkdir -p "${BUILD_OUTPUT}/EFI/BOOT/" || RC=$?
1055       cp "${CHROOT_OUTPUT}/boot/bootia32.efi" "${BUILD_OUTPUT}/EFI/BOOT/bootia32.efi" || RC=$?
1056       eend $?
1057     else
1058       ewarn "No EFI boot files found, skipping." ; eend 0
1059     fi
1060
1061     [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
1062     if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
1063       log    "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
1064       eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
1065       bailout 8
1066     fi
1067
1068     # copy _required_ isolinux files
1069     if [ -d "${CHROOT_OUTPUT}/usr/lib/ISOLINUX" ] ; then
1070       copy_addon_file isolinux.bin /usr/lib/ISOLINUX isolinux
1071       for file in ${CHROOT_OUTPUT}/usr/lib/syslinux/modules/bios/*.c32 ; do
1072         copy_addon_file "$(basename "$file")"  /usr/lib/syslinux/modules/bios/ isolinux
1073       done
1074     else # syslinux versions <= 3:4.05+dfsg-6+deb8u1
1075       copy_addon_file isolinux.bin /usr/lib/syslinux isolinux
1076       copy_addon_file ifcpu64.c32  /usr/lib/syslinux isolinux
1077       copy_addon_file vesamenu.c32 /usr/lib/syslinux isolinux
1078     fi
1079
1080     # *always* copy files to output directory so the variables
1081     # get adjusted according to the build.
1082     cp ${TEMPLATE_DIRECTORY}/boot/isolinux/*  "$BUILD_OUTPUT"/boot/isolinux/
1083
1084     mkdir -p "${BUILD_OUTPUT}/boot/grub"
1085     cp -a ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
1086
1087     if [ -n "$NO_ADDONS" ] ; then
1088       rm -f "$BUILD_OUTPUT"/boot/grub/addons.cfg
1089       log   "Skipping installation of boot addons as requested via \$NO_ADDONS."
1090       einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
1091     else
1092       if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
1093         log   "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
1094         ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
1095       else
1096         # copy addons from system packages or grml-live-addons
1097         copy_addon_file ipxe.lkrn /usr/lib/ipxe addons
1098         copy_addon_file pci.ids /usr/share/misc addons
1099         copy_addon_file memtest86+.bin /boot addons
1100
1101         # since syslinux(-common) v3:6.03~pre1+dfsg-4 the files are in a
1102         # different directory :(
1103         if [ -d "${CHROOT_OUTPUT}/usr/lib/syslinux/modules/bios/" ] ; then
1104           syslinux_modules_dir=/usr/lib/syslinux/modules/bios/
1105         else
1106           syslinux_modules_dir=/usr/lib/syslinux
1107         fi
1108         for file in chain.c32 hdt.c32 mboot.c32 menu.c32; do
1109           copy_addon_file "${file}" "${syslinux_modules_dir}" addons
1110         done
1111
1112         copy_addon_file memdisk /usr/lib/syslinux addons
1113
1114         # make memtest filename FAT16/8.3 compatible
1115         mv "${BUILD_OUTPUT}/boot/addons/memtest86+.bin" \
1116           "${BUILD_OUTPUT}/boot/addons/memtest"
1117
1118         # copy only files so we can handle bsd4grml on its own
1119         for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
1120           test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
1121         done
1122
1123         if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
1124           log   "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
1125           einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
1126         else
1127           if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
1128             cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
1129           else
1130             log   "Missing addon file: bsd4grml"
1131             ewarn "Missing addon file: bsd4grml" ; eend 0
1132           fi
1133         fi
1134
1135       fi # no "$TEMPLATE_DIRECTORY"/boot/addons
1136     fi # NO_ADDONS
1137
1138     # generate loopback.cfg config file without depending on grub's regexp module
1139     # which isn't available in Debian/squeeze
1140     echo "## grub2 loopback configuration" > "${BUILD_OUTPUT}"/boot/grub/loopback.cfg
1141     echo "source /boot/grub/header.cfg" >> "${BUILD_OUTPUT}"/boot/grub/loopback.cfg
1142     for config in "${BUILD_OUTPUT}"/boot/grub/*_default.cfg "${BUILD_OUTPUT}"/boot/grub/*_options.cfg ; do
1143       [ -r "$config" ] || continue
1144       echo "source ${config##$BUILD_OUTPUT}" >> "${BUILD_OUTPUT}"/boot/grub/loopback.cfg
1145     done
1146     if [ -z "$NO_ADDONS" ] ; then
1147       echo "source /boot/grub/addons.cfg" >> "${BUILD_OUTPUT}"/boot/grub/loopback.cfg
1148     fi
1149     echo "source /boot/grub/footer.cfg" >> "${BUILD_OUTPUT}"/boot/grub/loopback.cfg
1150
1151     # copy grub files from target
1152     mkdir -p "${BUILD_OUTPUT}"/boot/grub/i386-pc/
1153     cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/*-pc/*.mod "${BUILD_OUTPUT}"/boot/grub/i386-pc/
1154     cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/*-pc/*.o "${BUILD_OUTPUT}"/boot/grub/i386-pc/
1155     cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/*-pc/*.lst "${BUILD_OUTPUT}"/boot/grub/i386-pc/
1156     cp -a "${CHROOT_OUTPUT}"/usr/share/grub/ascii.pf2 "${BUILD_OUTPUT}"/boot/grub/
1157     cp -a "${CHROOT_OUTPUT}"/boot/grub/core.img "${BUILD_OUTPUT}"/boot/grub/
1158     cp -a "${CHROOT_OUTPUT}"/boot/grub/grub.img "${BUILD_OUTPUT}"/boot/grub/
1159
1160     # copy modules for UEFI grub, 64-bit
1161     mkdir -p "${BUILD_OUTPUT}"/boot/grub/x86_64-efi/
1162     cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/x86_64-efi/*.{mod,lst} "${BUILD_OUTPUT}"/boot/grub/x86_64-efi/
1163
1164     # copy modules for UEFI grub, 32-bit
1165     mkdir -p "${BUILD_OUTPUT}"/boot/grub/i386-efi/
1166     cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/i386-efi/*.{mod,lst} "${BUILD_OUTPUT}"/boot/grub/i386-efi/
1167
1168     if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
1169       log    "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
1170       eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
1171       bailout 9
1172     fi
1173
1174     mkdir -p "$BUILD_OUTPUT"/GRML/"${GRML_NAME}"/
1175     cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/"${GRML_NAME}"/
1176
1177     # adjust boot splash information:
1178     RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
1179     RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
1180     RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
1181
1182     if [ -r "$BUILD_OUTPUT"/GRML/"${GRML_NAME}"/grml-version ] ; then
1183       sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/"${GRML_NAME}"/grml-version
1184       sed -i "s/%DATE%/$DATE/"                                      "$BUILD_OUTPUT"/GRML/"${GRML_NAME}"/grml-version
1185     fi
1186
1187     # make sure the squashfs filename is set accordingly:
1188     SQUASHFS_NAME="$GRML_NAME.squashfs"
1189
1190     # adjust all variables in the templates with the according distribution information
1191     adjust_boot_files "${BUILD_OUTPUT}"/boot/isolinux/*.cfg \
1192       "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
1193       "${BUILD_OUTPUT}"/boot/grub/* \
1194       "${BUILD_OUTPUT}"/boot/ubuntu/*
1195
1196     for param in ARCH DATE DISTRI_INFO DISTRI_NAME DISTRI_SPLASH GRML_NAME SQUASHFS_NAME \
1197       RELEASE_INFO SHORT_NAME VERSION ; do
1198       for file in $(find "${BUILD_OUTPUT}" -name "*%$param%*") ; do
1199         value="$(eval echo '$'"$param")"
1200         mv ${file} ${file/\%${param}\%/$value}
1201       done
1202     done
1203
1204     # adjust bootsplash accordingly but make sure the string has the according length
1205     SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
1206     SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
1207     for file in f4 f5 ; do
1208       if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
1209         sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
1210         sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
1211       fi
1212     done
1213
1214     # generate addon list
1215     rm -f "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
1216     for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
1217       include_name=$(basename "$name")
1218       echo "include $include_name"  >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
1219     done
1220
1221     if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
1222       log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1223       echo "include grmlmain.cfg"    >  "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1224       echo "include default.cfg"     >  "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1225       echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1226       echo "include grml.cfg"        >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1227
1228       for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
1229         echo "include $(basename $f)"     >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1230       done
1231
1232       echo "include options.cfg"     >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1233       if [ -z "$NO_ADDONS" ] ; then
1234         echo "include addons.cfg"    >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1235       fi
1236       echo "include isoprompt.cfg"   >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1237       echo "include hd.cfg"          >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1238       echo "include hidden.cfg"      >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1239     else # assume we are building a custom distribution:
1240       log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
1241       einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
1242       if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
1243         log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
1244         eindent
1245         einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
1246         eoutdent
1247         eend $?
1248       else
1249         log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1250         echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1251         if [ -z "$NO_ADDONS" ] ; then
1252           echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1253         fi
1254       fi
1255     fi
1256
1257     # use old style console based isolinux method only if requested:
1258     if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
1259       log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
1260       einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
1261       if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
1262         einfo "include for console.cfg already found, nothing to do."
1263         eend 0
1264       else
1265         log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1266         einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1267         echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1268         eend $?
1269       fi
1270     else
1271       log 'Using graphical boot menu.'
1272       if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
1273         log "include for vesamenu.cfg already found, nothing to do."
1274       else
1275         log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1276         echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1277       fi
1278     fi
1279
1280     if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
1281       sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
1282     fi
1283
1284     DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
1285     if ! [ -r "$DPKG_LIST" ] ; then
1286       ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
1287     else
1288       einfo "Storing package list information as /GRML/${GRML_NAME}/packages.txt on ISO."
1289       cp "$DPKG_LIST" "${BUILD_OUTPUT}"/GRML/"${GRML_NAME}"/packages.txt
1290       eend $?
1291     fi
1292
1293     # autostart for Windows:
1294     if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
1295       cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
1296     fi
1297
1298     FORCE_ISO_REBUILD=true
1299     einfo "Finished execution of stage 'boot'" ; eend 0
1300   fi # BOOTSTRAP_ONLY
1301 else
1302   log    'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
1303   eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
1304   bailout
1305 fi
1306
1307 # support installation of local files into the chroot/ISO
1308 if [ -n "$CHROOT_INSTALL" ] ; then
1309   if ! [ -d "$CHROOT_INSTALL" ] ; then
1310      log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1311      ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1312   else
1313      log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1314      einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1315      rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
1316      eend $?
1317      einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
1318      FORCE_ISO_REBUILD=true
1319   fi
1320 fi
1321
1322 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
1323    log   "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
1324    ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
1325 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
1326    log   "Skipping stage 'squashfs' as requested via option -q or -N"
1327    ewarn "Skipping stage 'squashfs' as requested via option -q or -N" ; eend 0
1328 else
1329    mkdir -p "$BUILD_OUTPUT"/live/"${GRML_NAME}"/
1330    # make sure we don't leave (even an empty) base.tgz:
1331    [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
1332
1333    # if unconfigured default to squashfs-tools' mksquashfs binary
1334    if [ -z "$SQUASHFS_BINARY" ] ; then
1335       SQUASHFS_BINARY='mksquashfs'
1336    fi
1337
1338    if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
1339       log    "Using mksquashfs binary ${SQUASHFS_BINARY}"
1340       einfo  "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
1341    else
1342       log    "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
1343       eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
1344       bailout
1345    fi
1346
1347    # use sane defaults if $SQUASHFS_OPTIONS isn't set
1348    if [ -z "$SQUASHFS_OPTIONS" ] ; then
1349      # use blocksize 256k as this gives best result with regards to time + compression
1350      SQUASHFS_OPTIONS="-b 256k"
1351
1352      # set lzma/xz compression by default, unless -z option has been specified on command line
1353      if [ -z "$SQUASHFS_ZLIB" ] ; then
1354         SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp xz"
1355      else
1356         SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp gzip"
1357      fi
1358    fi
1359
1360    # support exclusion of files via exclude-file:
1361    if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
1362       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE -wildcards"
1363    fi
1364
1365    # get rid of unnecessary files when building grml-small for final release:
1366    if echo "$CLASSES" | grep -q GRML_SMALL ; then
1367       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
1368    fi
1369
1370    # log stuff
1371    SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
1372
1373    # informational stuff
1374    [ -n "$SQUASHFS_OPTIONS" ]  && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
1375    [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
1376    einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
1377
1378    log "$SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/${GRML_NAME}/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS"
1379
1380    if $SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/"${GRML_NAME}"/"${GRML_NAME}".squashfs \
1381       -noappend $SQUASHFS_OPTIONS 2>"${SQUASHFS_STDERR}" ; then
1382       echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/"${GRML_NAME}"/filesystem.module
1383       log "Finished execution of stage 'squashfs' [$(date)]"
1384       einfo "Finished execution of stage 'squashfs'" ; eend 0
1385    else
1386       log    "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1387       log    "$(cat $SQUASHFS_STDERR)"
1388       eerror "Error: there was a critical error executing stage 'squashfs':"
1389       cat    "${SQUASHFS_STDERR}"
1390       eend 1
1391       bailout
1392    fi
1393
1394    FORCE_ISO_REBUILD=true
1395 fi
1396
1397 # create md5sum file:
1398 if [ -z "$BOOTSTRAP_ONLY" ] ; then
1399   ( cd $BUILD_OUTPUT/GRML/"${GRML_NAME}" &&
1400   find ../.. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1401 fi
1402 # }}}
1403
1404 # ISO_OUTPUT - mkisofs {{{
1405 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1406 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1407
1408 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1409    BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1410    if [ "$HYBRID_METHOD" = "isohybrid" ] ; then
1411      EFI_ARGS="-isohybrid-mbr /usr/lib/ISOLINUX/isohdpfx.bin -eltorito-alt-boot -e boot/efi.img -no-emul-boot -isohybrid-gpt-basdat"
1412    fi
1413 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1414    BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1415 fi
1416
1417 # Work around http://bts.grml.org/grml/issue945
1418 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1419   log   "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1420   ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1421   HYBRID_METHOD='grub2'
1422   eend 0
1423 fi
1424
1425 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ]  ; then
1426    log   "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1427    ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1428 elif [ -n "$SKIP_MKISOFS" ] ; then
1429    log   "Skipping stage 'iso build' as requested via option -n or -N"
1430    ewarn "Skipping stage 'iso build' as requested via option -n or -N" ; eend 0
1431 else
1432    mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1433
1434    if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1435       log   "Forcing rebuild of ISO because files on ISO have been modified."
1436       einfo "Forcing rebuild of ISO because files on ISO have been modified."
1437    fi
1438
1439    # support xorriso as well mkisofs and genisoimage
1440    if which xorriso >/dev/null 2>&1 ; then
1441       MKISOFS='xorriso -as mkisofs'
1442     elif which mkisofs >/dev/null 2>&1; then
1443       MKISOFS='mkisofs'
1444    elif which genisoimage >/dev/null 2>&1; then
1445       MKISOFS='genisoimage'
1446    else
1447       log    "Error: neither xorriso nor mkisofs nor genisoimage available - can not create ISO."
1448       eerror "Error: neither xorriso nor mkisofs nor genisoimage available - can not create ISO." ; eend 1
1449       bailout
1450    fi
1451
1452    einfo "Using ${MKISOFS} to build ISO." ;  eend 0
1453    case "${ARCH}-${MKISOFS}" in
1454      # using -eltorito-alt-boot is limited to xorriso for now
1455      amd64-xorriso*)
1456        eindent
1457
1458        if ! dpkg --compare-versions $(dpkg-query -W -f='${Version}\n' xorriso 2>/dev/null) gt-nl 1.1.6-1 ; then
1459          log   "Disabling (U)EFI boot support because xorriso version is too old."
1460          ewarn "Disabling (U)EFI boot support because xorriso version is too old." ; eend 0
1461        else
1462          if [ -r "${BUILD_OUTPUT}"/boot/efi.img ] ; then
1463            einfo "Enabling (U)EFI boot."
1464            log   "Enabling (U)EFI boot."
1465            BOOT_ARGS="$BOOT_ARGS -boot-info-table -eltorito-alt-boot -e boot/efi.img -no-emul-boot"
1466            eend $?
1467          else
1468            log   "Disabling (U)EFI boot support because /boot/efi.img is missing."
1469            ewarn "Disabling (U)EFI boot support because /boot/efi.img is missing." ; eend 0
1470          fi
1471        fi
1472
1473        eoutdent
1474        ;;
1475    esac
1476
1477    CURRENT_DIR=$(pwd)
1478    if cd "$BUILD_OUTPUT" ; then
1479       if [ "$BOOT_METHOD" = "grub2" ]; then
1480          # make a 2048-byte bootsector for El Torito
1481          dd if=/dev/zero of=boot/grub/toriboot.bin bs=512 count=4 2>/dev/null
1482          # those are in 2048-byte sectors, so 1 16 matches 4 63 below
1483          echo 1 16 | mksh "${SCRIPTS_DIRECTORY}/bootgrub.mksh" -B 11 | \
1484             dd of=boot/grub/toriboot.bin conv=notrunc 2>/dev/null
1485       fi
1486       log "$MKISOFS -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J $BOOT_ARGS $EFI_ARGS -no-pad -o ${ISO_OUTPUT}/${ISO_NAME} ."
1487       $MKISOFS -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1488               -l -r -J $BOOT_ARGS $EFI_ARGS -no-pad \
1489               -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1490       # both of these need core.img there, so it’s easier to write it here
1491       if [ "$BOOT_METHOD" = "grub2" ] || [ "$HYBRID_METHOD" = "grub2" ]; then
1492          # must be <= 30720 bytes
1493          dd if=boot/grub/core.img of="${ISO_OUTPUT}/${ISO_NAME}" \
1494            conv=notrunc bs=512 seek=4 2>/dev/null
1495       fi
1496
1497       # pad the output ISO to multiples of 256 KiB for partition table support
1498       siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1499       cyls=$((siz / 512 / 32 / 16 + 1))   # C=$cyls H=16 S=32
1500       siz=$((cyls * 16 * 32 * 512))   # size after padding
1501       dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1502          of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1503
1504       # support disabling hybrid ISO image
1505       if [ "$HYBRID_METHOD" = "disable" ] ; then
1506         log   "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1507         einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1508         eend 0
1509       elif [ "$HYBRID_METHOD" = "manifold" ] || [ "$HYBRID_METHOD" = "grub2" ] ; then
1510         # isoinfo is part of both mkisofs and genisoimage so we're good
1511         bootoff=$(isoinfo -l -i "${ISO_OUTPUT}/${ISO_NAME}" | \
1512           sed -n '/^.*\[ *\([0-9]*\)[] ].* ISOLINUX.BIN[;1]* *$/s//\1/p')
1513
1514         if ! [ -r boot/grub/core.img ] ; then
1515           log   "boot/grub/core.img not found, not creating manifold boot ISO file"
1516           ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1517         elif [ "${bootoff:-0}" -lt 1 ] ; then
1518           log   "isolinux.bin not found on the ISO file, disabling manifold boot"
1519           ewarn "isolinux.bin not found on the ISO file, disabling manifold boot"
1520         else
1521           if [ "$HYBRID_METHOD" = "grub2" ] ; then
1522             log   "Creating hybrid ISO file with manifold/grub2 method"
1523             einfo "Creating hybrid ISO file with manifold/grub2 method"
1524             # 512 bytes: MBR, partition table, load GRUB 2
1525             echo 4 63 | mksh "${SCRIPTS_DIRECTORY}/bootgrub.mksh" -A -M 4:0x96 -g $cyls:16:32
1526           else
1527             log   "Creating hybrid ISO file with manifold method"
1528             einfo "Creating hybrid ISO file with manifold method"
1529             # read only one but 2048-byte sized (scale: << 2) sector
1530             echo $bootoff $bootoff | \
1531               mksh ${SCRIPTS_DIRECTORY}/bootilnx.mksh -A -M 4:0x96 -g $cyls:16:32 -S 2
1532           fi | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1533           eend $?
1534         fi
1535       elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
1536         : # nothing to do, handled via $MKISOFS $EFI_ARGS already
1537       else
1538         bailout 12 "Unknown HYBRID_METHOD [${HYBRID_METHOD}]. Supported values: disable, isohybrid, grub2, manifold"
1539       fi
1540
1541       # generate ISO checksums if we are using class 'RELEASE':
1542       case $CLASSES in *RELEASE*)
1543          [ "$RC" = 0 ] && \
1544          (
1545            if cd $ISO_OUTPUT ; then
1546              md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1547              touch -r ${ISO_NAME} ${ISO_NAME}.md5
1548              sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1549              touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1550              sha256sum ${ISO_NAME} > ${ISO_NAME}.sha256 && \
1551              touch -r ${ISO_NAME} ${ISO_NAME}.sha256
1552              sha512sum ${ISO_NAME} > ${ISO_NAME}.sha512 && \
1553              touch -r ${ISO_NAME} ${ISO_NAME}.sha512
1554            fi
1555          )
1556          ;;
1557       esac
1558
1559       cd "$CURRENT_DIR"
1560    fi
1561
1562    if [ "$RC" = 0 ] ; then
1563       log   "Finished execution of stage 'iso build' [$(date)]"
1564       einfo "Finished execution of stage 'iso build'" ; eend 0
1565    else
1566       log    "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1567       eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1568       bailout $RC
1569    fi
1570 fi
1571 # }}}
1572
1573 # netboot package {{{
1574 create_netbootpackage() {
1575   local OUTPUT_FILE="${NETBOOT}/grml_netboot_package_${GRML_NAME}_${VERSION}.tar.bz2"
1576
1577   if [ -f "${OUTPUT_FILE}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
1578     log   "Skipping stage 'netboot' as $OUTPUT_FILE exists already."
1579     ewarn "Skipping stage 'netboot' as $OUTPUT_FILE exists already." ; eend 0
1580     return 0
1581   elif [ -n "$SKIP_NETBOOT" ] ; then
1582     log   "Skipping stage 'netboot' as requested via option -Q"
1583     ewarn "Skipping stage 'netboot' as requested via option -Q" ; eend 0
1584     return 0
1585   fi
1586
1587   mkdir -p "$NETBOOT"
1588
1589   # since syslinux v3:6.03~pre1+dfsg-4 the pxelinux.0 has been split into a
1590   # separate pxelinux package
1591   if [ -d "${CHROOT_OUTPUT}/usr/lib/PXELINUX/" ] ; then
1592     local pxelinux_dir=/usr/lib/PXELINUX
1593   else
1594     local pxelinux_dir=/usr/lib/syslinux
1595   fi
1596
1597   if ! [ -r "${CHROOT_OUTPUT}/${pxelinux_dir}/pxelinux.0" ] ; then
1598     ewarn "File ${pxelinux_dir}/pxelinux.0 not found in build chroot." ; eend 0
1599     eindent
1600     einfo "Install syslinux[-common]/pxelinux package in chroot to get a netboot package."
1601     eoutdent
1602     return 0
1603   fi
1604
1605   local OUTPUTDIR="${NETBOOT}/build_tmp"
1606   local WORKING_DIR="${OUTPUTDIR}/grml_netboot_package_${GRML_NAME}_${VERSION}/tftpboot/"
1607
1608   mkdir -p "$WORKING_DIR"
1609
1610   cp "${CHROOT_OUTPUT}"/boot/vmlinuz-*    "$WORKING_DIR"/vmlinuz
1611   cp "${CHROOT_OUTPUT}"/boot/initrd.img-* "$WORKING_DIR"/initrd.img
1612   cp "${CHROOT_OUTPUT}/${pxelinux_dir}/pxelinux.0" "${WORKING_DIR}/pxelinux.0"
1613
1614   if [ -r "${CHROOT_OUTPUT}"/usr/lib/syslinux/modules/bios/ldlinux.c32 ] ; then
1615     cp "${CHROOT_OUTPUT}"/usr/lib/syslinux/modules/bios/ldlinux.c32 "${WORKING_DIR}"/
1616   fi
1617
1618   mkdir -p "${WORKING_DIR}/pxelinux.cfg"
1619   if [ -r "${BUILD_OUTPUT}/boot/isolinux/netboot.cfg" ] ; then
1620     cp "${BUILD_OUTPUT}/boot/isolinux/netboot.cfg" "${WORKING_DIR}/pxelinux.cfg/default"
1621   else
1622     log   "File ${BUILD_OUTPUT}/boot/isolinux/netboot.cfg not found."
1623     ewarn "File ${BUILD_OUTPUT}/boot/isolinux/netboot.cfg not found."
1624     eindent
1625     log   "Hint: Are you using custom templates which do not provide netboot.cfg?"
1626     ewarn "Hint: Are you using custom templates which do not provide netboot.cfg?" ; eend 0
1627     eoutdent
1628   fi
1629
1630   if tar -C "$OUTPUTDIR" -jcf "${OUTPUT_FILE}" "grml_netboot_package_${GRML_NAME}_${VERSION}" ; then
1631     (
1632       cd $(dirname "${OUTPUT_FILE}")
1633       sha1sum $(basename "${OUTPUT_FILE}") > "${OUTPUT_FILE}.sha1"
1634       sha256sum $(basename "${OUTPUT_FILE}") > "${OUTPUT_FILE}.sha256"
1635       sha512sum $(basename "${OUTPUT_FILE}") > "${OUTPUT_FILE}.sha512"
1636     )
1637     einfo "Generated netboot package ${OUTPUT_FILE}" ; eend 0
1638     rm -rf "${OUTPUTDIR}"
1639   else
1640     rm -rf "${OUTPUTDIR}"
1641     eerror "Could not generate netboot package ${OUTPUT_FILE}" ; eend 1
1642     bailout 21
1643   fi
1644 }
1645
1646 create_netbootpackage
1647 # }}}
1648
1649 # log build information to database if grml-live-db is installed and enabled {{{
1650 dpkg_to_db() {
1651 if [ -d /usr/share/grml-live-db ] ; then
1652
1653   # safe defaults
1654   DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1655   [ -n "$DPKG_DATABASE" ]  || DPKG_DATABASE=/var/log/grml-live.db
1656   [ -n "$DPKG_DBSCRIPT" ]  || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1657   [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1658
1659   if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1660     log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1661     eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1662     bailout 14
1663   fi
1664
1665   # disable by default for now, not sure whether really everyone is using a local db file
1666   #if ! touch "$DPKG_DATABASE" ; then
1667   #  eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1668   #  bailout 14
1669   #fi
1670
1671   if ! [ -r "$DPKG_LIST" ] ; then
1672      log   "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1673      ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1674   else
1675      einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1676      log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1677      log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1678      eindent
1679
1680      if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1681        einfo "$DB_INFO"
1682        eend 0
1683      else
1684        eerror "$DB_INFO"
1685        eend 1
1686      fi
1687
1688      eoutdent
1689   fi
1690
1691 fi
1692 }
1693 # }}}
1694
1695 # finalize {{{
1696 if [ -n "${start_seconds}" ] ; then
1697   end_seconds="$(date +%s)"
1698   SECONDS="$(( end_seconds - start_seconds ))"
1699 fi
1700 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1701
1702 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1703
1704 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1705 bailout 0
1706 # }}}
1707
1708 ## END OF FILE #################################################################
1709 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2