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