#! /bin/bash

# $Id: make-fai-bootfloppy,v 1.47 2003/10/10 09:18:36 lange Exp $
#*********************************************************************
#
# make-fai-bootfloppy -- create a boot floppy for FAI
#
# This script is part of FAI (Fully Automatic Installation)
# (c) 2000-2003 by Thomas Lange, lange@informatik.uni-koeln.de
# Universitaet zu Koeln
#
#*********************************************************************
# 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.
#*********************************************************************

version="version 2.3, 9-oct-2003"
set -e
timeout=15
mkimage=0
floppydev=/dev/fd0
mountpoint=/floppy
mountopts="-t ext2"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
umount_dirs() {

    cd /
    umount "$mountpoint" 2>/dev/null || true
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
die() {

    echo -e "$@"
    exit 99
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
determine_kernel_version() {

    local num all
    all=$(ls $NFSROOT/boot/vmlinuz-*)
    if [ `echo $all | wc -l` = 1 ]; then
	KERNELVERSION=$(echo "kernel version $all" | sed -e 's#.*/vmlinuz-##')
    else
	die "Can't determine kernel version for $all"
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
usage() {

    cat <<EOF
make-fai-bootfloppy, create a boot floppy for FAI. $version

   Copyright (C) 2000-2003 by Thomas Lange

   Usage: make-fai-bootfloppy [parameter]

   -d LABEL   use LABEL when selection the default boot kernel (and parameters).
              a for any boot protocol (kernel tries all compiled in)
	      b for BOOTP
	      d for DHCP
	      f use fixed IP, needs companion option -s
              r for RARP
	      Without this option rarp and bootp are used.
   -h         print this message.
   -f FILE    make a 1440k floppy image in FILE
   -g         use GRUB loader on bootfloppy (default)
   -l         use LILO loader on bootfloppy
   -m DIR     use DIR as mountpoint [/floppy]
   -s HOST    use this static ip for FAI client; try to get all info from DNS
   -v         print verbose output

DESCRIPTION
   Creates a boot floppy for booting a FAI install client.
   No arguments are needed but you must be root.
   You may need to use "nfsroot=serverip:path" if you use RARP or if your
   BOOTP or DHCP server does not pass that info to the clients.
   All parameters are passed to the kernel via append in lilo.conf,
   or kernel commandline in grub.conf .

EXAMPLE
    Create a generic boot floppy for James ;-)
    # make-fai-bootfloppy "FAI_FLAGS=verbose,createvt,sshd BOND=007"

    To make a boot floppy for my old SMC EtherCard Plus Elite 16T, I use
    # make-fai-bootfloppy "reserve=0x300,32 ether=10,0x300,eth0"

    To make a boot floppy using the DHCP protocol
    # make-fai-bootfloppy -d d

EOF
    exit 0
}
# - - - - - - - - - - - - - - - - - - - - - - - - - -
determine_network_parameters() {

    local dev ndevices devices 
    ndevices=0
    devices=`egrep -v "lo:|^Inter-|^ face" /proc/net/dev | awk -F: 'ORS=" " {print $1}'`
    for dev in $devices; do
	ndevices=$(($ndevices+1))
    done
    [ $ndevices = 0 ] && die "No network interface found. Can't determine IP address."
    if [ $ndevices = 1 ]; then
	SERVERINTERFACE=$dev
    else
	case $BTYPE in
	    b|d)
		# assume BOOTP/DHCP server will pass NFS info to client
		;;
	    *)
		# find out which IP to use...
		while [ -z "$SERVERINTERFACE" ]; do
		    echo "This FAI server has multiple network interfaces: $devices"
		    echo -n "Specify which one FAI clients will connect to (eg. eth1): "
		    read SERVERINTERFACE
		done
		;;
	esac
    fi

    SERVERIP=`LC_ALL=C ifconfig $SERVERINTERFACE | perl -ne '/inet addr:([0-9\.]+)/ && print $1'`

    if [ -n "${TARGETHOST}" ] ; then
	TARGETIP=`perl -e 'use Socket; use Net::hostent; printf "%s\n", inet_ntoa((gethost($ARGV[0]))->addr);' "${TARGETHOST}"`
	TARGETHOST=`perl -e 'use Socket; print gethostbyaddr(inet_aton($ARGV[0]), AF_INET)."\n";' ${TARGETHOST}`
	BROADCAST=`LC_ALL=C ifconfig $SERVERINTERFACE | perl -ne '/Bcast:([0-9\.]+)/ && print $1'`
	NETMASK=`LC_ALL=C ifconfig $SERVERINTERFACE | perl -ne '/Mask:([0-9\.]+)/ && print $1'`
	GATEWAY=`LC_ALL=C route -n | grep '^0\.0\.0\.0' | awk '{ print $2 }'`
	fixedparams="ip=${TARGETIP}:${SERVERIP}:${GATEWAY}:${NETMASK}:${TARGETHOST}::off" 
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
lilo_floppy() {

# make a boot floppy using lilo

    echo "Creating the boot floppy with lilo."
    mkdir $mountpoint/boot $mountpoint/etc
    rmdir $mountpoint/lost+found

    cd $NFSROOT && cp -dp boot/boot-menu.b boot/vmlinuz-$KERNELVERSION $mountpoint/boot
    ln -s boot/vmlinuz-$KERNELVERSION $mountpoint/vmlinuz
    ln -fs $mountpoint/boot/boot-menu.b $mountpoint/boot/boot.b

    [ $mkimage -eq 1 ] && cat > $mountpoint/etc/lilo.conf <<-EOF
    disk=$(mount | grep $mountpoint | sed -e 's/.*loop=\([^)]*\))/\1/')
    bios=0x00
    cylinders=80
    heads=2
    sectors=18
EOF

    cat >> $mountpoint/etc/lilo.conf <<-EOF

    boot=$floppydev
    install=$mountpoint/boot/boot-menu.b
    map=$mountpoint/boot/map
    delay=$timeout
    compact
    read-only

    default=$lilodef

    image=$mountpoint/vmlinuz
    append="ip=::::::any root=/dev/nfs $params"
    label=FAI-ANY

    image=$mountpoint/vmlinuz
    append="ip=::::::both root=/dev/nfs $params"
    label=FAI-BOTH

    image=$mountpoint/vmlinuz
    append="ip=::::::bootp root=/dev/nfs $params"
    label=FAI-BOOTP

    image=$mountpoint/vmlinuz
    append="ip=::::::dhcp root=/dev/nfs $params"
    label=FAI-DHCP

    image=$mountpoint/vmlinuz
    label=FAI-FIXED-IP
    append="root=/dev/nfs nfsroot=$SERVERIP:$NFSROOT $fixedparams $params"

    image=$mountpoint/vmlinuz
    append="ip=::::::rarp root=/dev/nfs $params"
    label=FAI-RARP
EOF
    $NFSROOT/sbin/lilo -C $mountpoint/etc/lilo.conf
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
grub_floppy() {

    echo "Creating the boot floppy with grub."
    # make a boot floppy using grub
    kernel=vmlinuz-$KERNELVERSION
    mkdir -p $mountpoint/boot/grub
    cp -p $NFSROOT/usr/lib/grub/i386-pc/stage? $mountpoint/boot/grub
    cp $NFSROOT/boot/$kernel $mountpoint

    grubconf="
default $grubdef
#default saved
timeout $timeout

title FAI-ANY
kernel (fd0)/$kernel root=/dev/nfs ip=::::::any $params
savedefault

title FAI-BOTH
kernel (fd0)/$kernel root=/dev/nfs ip=::::::both $params
savedefault

title FAI-BOOTP
kernel (fd0)/$kernel root=/dev/nfs ip=::::::bootp $params
savedefault

title FAI-DHCP
kernel (fd0)/$kernel root=/dev/nfs ip=::::::dhcp $params
savedefault

title FAI-FIXED-IP
kernel (fd0)/$kernel root=/dev/nfs nfsroot=$SERVERIP:$NFSROOT ip=::::::both $fixedparams $params
savedefault

title FAI-RARP
kernel (fd0)/$kernel root=/dev/nfs ip=::::::rarp $params
savedefault
"
    echo "$grubconf" > $mountpoint/boot/grub/menu.lst
    umount $mountpoint
    $NFSROOT/sbin/grub --batch --device-map=/dev/null >/dev/null <<EOF
device (fd0) $floppydev
root (fd0)
setup (fd0)
quit
EOF
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# main part

while getopts "lgvf:s:m:hd:" opt ; do
    case "$opt" in
	l) lilo=1 ;;
	g) grub=1 ;;
        h) usage ;;
	f) mkimage=1; floppydev="$OPTARG" ;;
	m) mountpoint="$OPTARG" ;;
	s) TARGETHOST="$OPTARG" ;;
	d) BTYPE="$OPTARG" ;;
	v) verbose=1 ;;
        ?) echo "Error parsing arguments"; exit 1;;
    esac
done
shift `expr $OPTIND - 1`
case "$BTYPE" in
    a) lilodef=FAI-ANY      ; grubdef=0 ;;
    b) lilodef=FAI-BOOTP    ; grubdef=2 ;;
    d) lilodef=FAI-DHCP     ; grubdef=3 ;;
    f) lilodef=FAI-FIXED-IP ; grubdef=4 ;;
    r) lilodef=FAI-RARP     ; grubdef=5 ;;
    *) lilodef=FAI-BOTH     ; grubdef=1 ;;
esac

[ $lilo ] && [ $grub ] && die "Specify only one of -l or -g"
[ $lilo ] || [ $grub ] || grub=1
[ `id -u` -eq 0 ] || die "You must be root! Or try $0 -h"

trap "umount_dirs" EXIT
# additional kernel parameter
params="$@"

. /etc/fai/fai.conf
determine_kernel_version
determine_network_parameters

if [ $mkimage -eq 1 ]; then 
    [ -e $floppydev ] && die "$floppydev already exists. Please remove it and restart again."
    dd if=/dev/zero of=$floppydev bs=1024 count=1440
    mountopts="$mountopts -o loop"
    mkfsopt=-F
else
    # blank first sector of floopy
    dd if=/dev/zero of=$floppydev bs=512 count=1 2>/dev/null
fi

# pay attention: if -i option is too large, then too few inodes
# are created on the floppy. Check it with df -i
echo "Creating filesystem on floppy device $floppydev."
mke2fs $mkfsopt -q -i 40000 -m 0 $floppydev || \
  die "Can't create ext2 file system on $floppydev"
mount $mountopts $floppydev $mountpoint || die "Can't mount floppy $floppydev"

[ $lilo ] && lilo_floppy
[ $grub ] && grub_floppy
echo "Using IP address $SERVERIP of $SERVERINTERFACE for the fixed boot menu."

cat <<-EOF
	Writing boot data to floppy. The default boot label is: $liloboot
	The kernel configuration is $NFSROOT/boot/config-$KERNELVERSION.
EOF

[ "$params" ] && echo "Additional kernel parameters: $params"

[ "$verbose" ] && [ $lilo ] && {
    echo "The lilo.conf is:"
    echo
    cat $mountpoint/etc/lilo.conf
}
[ "$verbose" ] && [ $grub ] && {
    echo "The grub menu is:"
    echo
    echo "$grubconf"
}

