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