#!/bin/bash

# $Id: fai-cd 4106 2006-10-21 08:34:46Z siretart-guest $
#*********************************************************************
#
# fai-cd -- make a fai CD, a bootable CD that performs the FAI
#
# This script is part of FAI (Fully Automatic Installation)
# (c) 2004-2006 by Thomas Lange, lange@informatik.uni-koeln.de
# Universitaet zu Koeln
#
# based on a script called make-fai-bootcd by Niall Young <niall@holbytla.org>
#
#*********************************************************************
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# A copy of the GNU General Public License is available as
# `/usr/share/common-licences/GPL' in the Debian GNU/Linux distribution
# or on the World Wide Web at http://www.gnu.org/copyleft/gpl.html.  You
# can also obtain it by writing to the Free Software Foundation, Inc.,
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#*********************************************************************

set -e 
version="fai-cd 2.4.3, 6 october 2006"

burn=0
hidedirs="/usr/share/locale /usr/share/doc /var/lib/apt /var/cache/apt /usr/share/man /var/lib/dpkg/info /media/mirror/aptcache /media/mirror/.apt-move"

# we need FAI_CONFIGDIR, NFSROOT

trap "unhide_dirs;umount_dirs" EXIT ERR

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
usage() {

    cat <<-EOF
	$version. Copyright (C) 2004-2006 Thomas Lange
	Report bugs to <fai@informatik.uni-koeln.de>.

	Usage: fai-cd [OPTIONS] -m MIRRORDIR ISONAME
	Create a fai CD, a bootable CD that performs the FAI.
	Read the man pages pages fai-cd(8).
EOF
exit 0
}
# - - - - - - - - - - - - - - - - - - - - - - - - - -
die() {

    local e=$1   # first parameter is the exit code
    shift

    echo "ERROR: $@"    # print error message
    exit $e
}
# - - - - - - - - - - - - - - - - - - - - - - - - - -
create_initrd_image() {

    local kdir=$NFSROOT/lib/modules/$kernelversion

    echo "Creating initrd image with kernel $kernelversion"
    mkdir -p $tmp/boot/grub
    sed "s/_VERSION_/$isoversion/" < /etc/mkinitrd-cd/id.txt > $NFSROOT/id.txt
    mkinitrd-cd $kdir $tmp/boot/initrd.img full "$isoversion"
}
# - - - - - - - - - - - - - - - - - - - - - - - - - -
create_grub_image() {

    echo -n "Creating grub boot image ..."

    > $tmp/boot/RUNNING_FROM_FAICD
    [ -d /usr/lib/grub ] && cp /usr/lib/grub/i386-pc/stage2_eltorito $tmp/boot/grub/
    # for sarge
    [ -d /lib/grub ] && cp /lib/grub/i386-pc/stage2_eltorito $tmp/boot/grub/
    cp $grub_config $tmp/boot/grub/menu.lst
    # insert date into grub menu
    perl -pi -e "s/_VERSIONSTRING_/   $isoversion     /" $tmp/boot/grub/menu.lst
    cp $NFSROOT/boot/vmlinuz-$kernelversion $tmp/boot/vmlinuz
    cp $NFSROOT/boot/config-$kernelversion $tmp/boot/
    echo "done"
}
# - - - - - - - - - - - - - - - - - - - - - - - - - -
customize_nfsroot() {

    # hide some dirs to save space and make the CD image smaller
    local d

    mkdir $tmp/empty
    for d in $hidedirs; do
	if [ -d $NFSROOT/$d ]; then
	    [ "$debug" ] && echo "hiding $d"
	    mount --bind $tmp/empty $NFSROOT/$d
	fi
    done
}
# - - - - - - - - - - - - - - - - - - - - - - - - - -
unhide_dirs() {

    set +e
    for d in $hidedirs; do
	if [ -d $NFSROOT/$d ]; then
	    [ "$debug" ] && echo "disclosing $d"
	    umount $NFSROOT/$d 2>/dev/null
	fi
    done
    set -e
}
# - - - - - - - - - - - - - - - - - - - - - - - - - -
umount_dirs() {

    set +e
    local d
    local dirs="boot $FAI media/mirror etc/apt/sources.list"
    for d in $dirs; do
	umount $NFSROOT/$d 2>/dev/null
    done
    set -e
}
# - - - - - - - - - - - - - - - - - - - - - - - - - -
create_iso() {

    # Create the El Torito bootable iso9660 cdrom image

    echo "Mounting all needed parts"

    mkdir -p $NFSROOT/media/mirror
    mount --bind $tmp/boot $NFSROOT/boot
    mount --bind $FAI_CONFIGDIR $NFSROOT/$FAI && echo "Config space $FAI_CONFIGDIR mounted"
    mount --bind $mirrordir $NFSROOT/media/mirror && echo "Mirror $mirrordir mounted"
# TODO: customize /etc/apt, copy apt preferences etc.

    # this will be the sources.list for the CD
    tmp1=$(mktemp) || exit 12
    cat > $tmp1 <<EOF
# mirror location for fai CD, file generated by fai-cd
EOF

    dists=`find $mirrordir -name "Packages*" | grep binary | sed 's/binary-.*//' | \
         sed "s#$mirrordir/*dists/##" | xargs -n 1 dirname | uniq `

    for i in $dists ; do
	comp=`find $mirrordir/dists/$i -maxdepth 2 -type d -name "binary-*" | \
        sed -e "s#$mirrordir/*dists/$i/##" -e 's#/binary-.*##' | tr '\n' " "`
	echo "deb file:/media/mirror $i $comp" >> $tmp1
    done

    mount --bind $tmp1 $NFSROOT/etc/apt/sources.list
    customize_nfsroot
    echo "Writing FAI CD-ROM image to $isoname. This may need some time."
    mkisofs -V "$vname" -A "$aname" -log-file /dev/null -quiet -R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -boot-info-table -c boot.catalog -o $isoname $NFSROOT || die 12 "mkisofs failed." 
    echo -n "ISO image size and filename: "; du -h $isoname
    rm $tmp1
    unhide_dirs
    umount_dirs
}
# - - - - - - - - - - - - - - - - - - - - - - - - - -
burniso() {

    cdrecord -v -eject $isoname
}
# - - - - - - - - - - - - - - - - - - - - - - - - - -
# main program

case `dpkg --print-installation-architecture` in
    i386|amd64) : ;;
       *) die 11 "fai-cd only works on i386 and maybe on amd64 architecture. Exiting."
esac

# Parse commandline options
while getopts "hg:bm:C:" opt ; do
    case "$opt" in
        C) cfdir=$OPTARG ;;
	h)  usage ;;
	g)  grub_config="$OPTARG" ;;
	m)  mirrordir="$OPTARG" ;;
	b)  burn=1 ;;
	?)  usage ;;
    esac
done
shift $(($OPTIND - 1))
isoname=$1

[ "$#" -eq 0 ]        && die 2 "Please specify the output file for the ISO image."
[ -z "$mirrordir" ]   && die 4 "Please specify the directory of your mirror using -m"
[ -d "$mirrordir" ]   || die 5 "$mirrordir is not a directory"
[ -f "$isoname" ]     && die 3 "Outputfile $isoname already exists. Please remove it."
[ $(id -u) != "0" ]   && die 9 "Run this program as root."

[ -x "$(which mkinitrd-cd)" ] || die 7 "mkinitrd-cd not found. Please install package."
[ -x "$(which mkisofs)" ] || die 8 "mkisofs not found. Please install package."

# use FAI_ETC_DIR from environment variable
if [ -n "$FAI_ETC_DIR" -a -z "$cfdir" ]; then
    echo "Using environment variable \$FAI_ETC_DIR."
fi
cfdir=${FAI_ETC_DIR:=/etc/fai}
cfdir=$(readlink -f $cfdir) # canonicalize path
if [ ! -d "$cfdir" ]; then
    echo "$cfdir is not a directory"
    exit 6
fi
[ "$verbose" ] && echo "Using configuration files from $cfdir"
. $cfdir/fai.conf
export NFSROOT=$(source $cfdir/make-fai-nfsroot.conf; echo $NFSROOT)
[ -d "$NFSROOT/etc/fai" ] || die 10 "Please create NFSROOT by calling make-fai-nfsroot or fai-setup."


if [ -z "$grub_config" ]; then
    grub_config="$cfdir/menu.lst"
else
    grub_config="$cfdir/$grub_config"
fi
[ -f "$grub_config" ] || die 13 "Grub menu file $grub_config not found."

[ -z "$FAI_CONFIGDIR" ]  && die 14 "Variable \$FAI_CONFIG not set."
[ -d $FAI_CONFIGDIR ] || die 15 "Can't find config space $FAI_CONFIGDIR."
[ -d $FAI_CONFIGDIR/class ] || die 16 "Config space $FAI_CONFIGDIR seems to be empty."

tmp=$(mktemp -t -d fai-cd.XXXXXX) || exit 13
kernelversion=$(ls -tr $NFSROOT/boot/vmlinu?-* | tail -1 | sed -e 's#.*/vmlinuz-##')

faiversion=$(dpkg --root=$NFSROOT -l fai-client|grep fai-client|awk '{print $3}')
isoversion="FAI $faiversion -- build $(date '+%c')"
vname="Fully Automatic Installation CD"
aname="Fully Automatic Installation by Thomas Lange, $isoversion"

create_initrd_image
create_grub_image
create_iso
rm -rf $tmp
[ "$burn" -eq 1 ] && burniso
exit 0
