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