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