#!/bin/bash

# mkbootdisk
#
# Written by Erik Troan <ewt@redhat.com>

pause=yes
unset kernel
device=/dev/fd0
unset verbose
unset kernelargs
unset mountopts
unset isoimage
unset realdev
size=1440
failed=0

MOUNTDIR=`mktemp -d /tmp/mkbootdisk.XXXXXX`
PATH=/sbin:$PATH
export PATH

VERSION=1.5.3

usage () {
    cat >&2 <<EOF
usage: `basename $0` [--version] [--noprompt] [--device <devicefile>] 
       [--verbose -v] [--iso] [--kernelargs <args>] [--size <size>]  <kernel>
       (ex: `basename $0` --device /dev/fd1 2.0.31)
EOF
    exit $1
}

while [ $# -gt 0 ]; do
    case $1 in
    --device)
        shift
        device=$1
        ;;
    --kernelargs)
        shift
        kernelargs=$1
        ;;
    --help)
        rm -rf $MOUNTDIR
        usage 0
        ;;
    --iso)
        isoimage=1
        ;;
    --size)
        shift
        size=$1
        ;;
    --noprompt)
        unset pause
        ;;
    -v)
        verbose=true
        ;;
    --verbose)
        verbose=true
        ;;
    --version)
        echo "mkbootdisk: version $VERSION"
        rm -rf $MOUNTDIR
        exit 0
        ;;
    *)
        if [ -z "$kernel" ]; then
        kernel=$1
        else
        rm -rf $MOUNTDIR
        usage
        fi
        ;;
    esac

    shift
done

[ -z "$kernel" ] && {
    rm -rf $MOUNTDIR
    usage 1
}

[ "$(uname -i)" == "x86_64" ] && [ -z $isoimage ] && {
    echo "Image for x86_64 architecture does not fit on 1.44MB floppy." >&2
    echo "Use \"--iso --device image.iso\" options to make a CD image." >&2
    exit 1
}

[ -d /lib/modules/$kernel ] || {
    echo "/lib/modules/$kernel is not a directory." >&2
    rm -rf $MOUNTDIR
    exit 1
}

[ -f /boot/vmlinuz-$kernel ] || {
    echo "/boot/vmlinuz-$kernel does not exist." >&2
    rm -rf $MOUNTDIR
    exit 1
}


rootdev=`awk '$1 ~ /^[^#]/ && $2 ~ /^\/$/ { print $1 ; exit }' /etc/fstab`

if [ $(echo $rootdev | cut -c1-6) = "LABEL=" ]; then
    rootlabel=$(echo $rootdev | cut -c7-)

    # whee, now we have to look through every partition looking for
    # the thing called $rootlabel, which could be raid. Ick.

    list=$(tail -n +3 /proc/partitions | awk '{ print $4 '} | grep '^md')
    list="$list $(tail -n +3 /proc/partitions | 
            awk '{ print $4 '} | grep -v '^md')"
    rootdev=""
    for dev in $list; do
    if tune2fs -l /dev/$dev >/dev/null 2>/dev/null; then
        label=$(tune2fs -l /dev/$dev 2>/dev/null | 
        grep "Filesystem volume name" | awk '{print $4}')
        if [ "$label" = $rootlabel ]; then
        rootdev=/dev/$dev
        break
        fi
    fi
    done
fi

if [ -z "$kernelargs" -a -x /sbin/grubby -a -f /boot/grub/grub.conf ]; then
    # sed gross... this grep's for the args= line and removes the args=" and "$
    defkernel=$(grubby --default-kernel)
    if [ -n "$defkernel" ]; then
    kernelargs=$(grubby --info "$defkernel" |
                 sed -n '/^args=/{s/^args="//;s/"$//;p;}')
    fi
fi

[ -z "$rootdev" ] && {
    echo 'Cannot find root partition in /etc/fstab.' >&2
    rm -rf $MOUNTDIR
    exit 1
}

rm -rf $MOUNTDIR
mkdir $MOUNTDIR || {
    echo "Failed to create $MOUNTDIR" >&2
    exit 1
}
[ -d $MOUNTDIR ] || {
    echo "$MOUNTDIR is not a directory!" >&2
    rm -rf $MOUNTDIR
    exit 1
}

if [ -n "$isoimage" ]; then
    cfgfile=$MOUNTDIR/isolinux/isolinux.cfg
    bootmsg=$MOUNTDIR/isolinux/boot.msg

    # create an iso image; the directory is all we need
    [ -n "$verbose" ] && echo -n "Installing isolinux... "
    mkdir $MOUNTDIR/isolinux
    cp /usr/lib/syslinux/isolinux.bin $MOUNTDIR/isolinux
    [ -n "$verbose" ] && echo done
else
    cfgfile=$MOUNTDIR/syslinux.cfg
    bootmsg=$MOUNTDIR/boot.msg

    # we need to create an msdos filesystem for syslinux

    if [ -b "$device" ]; then
    if [ -n "$pause" ]; then
        echo "Insert a disk in $device. Any information on the disk will be lost."
        echo -n "Press <Enter> to continue or ^C to abort: "
        read aline
    fi

    # this is copying some bits from below.  oh well
    realdev=$device
    device=`/bin/mktemp /tmp/mkbootdisk.XXXXXX`
    dd if=/dev/zero of=$device bs=1024 count=$size 2> /dev/null
    mountopts=loop
    elif [ -f "$device" ]; then
    echo "$device exists but is not a block device."
    rmdir $MOUNTDIR
    exit 1
    else 
    dd if=/dev/zero of=$device bs=1024 count=$size 2> /dev/null
    mountopts=loop
    fi

    [ -n "$verbose" ] && echo -n "Formatting $device... "
    mkdosfs -r 16 -I $device > /dev/null || {
    echo "Failed to format $device" >&2
    rmdir $MOUNTDIR
    [ -n "$realdev" ] && rm -f "$device"
    exit 1
    }
    
    syslinux $device
    [ -n "$verbose" ] && echo "done."

    mount -o "$mountopts" -t vfat $device $MOUNTDIR || {
    rmdir $MOUNTDIR
    [ -n "$realdev" ] && rm -f "$device"
    exit 1
    }
fi


if [ -n "$isoimage" ]; then
    BOOTDESTDIR=$MOUNTDIR/isolinux
else
    BOOTDESTDIR=$MOUNTDIR
fi

[ -n "$verbose" ] && echo -n "Copying /boot/vmlinuz-$kernel... "
cp -p /boot/vmlinuz-$kernel $BOOTDESTDIR/vmlinuz
[ $? = 0 ] || failed=1
[ -n "$verbose" ] && echo "done."

[ -n "$verbose" ] && echo -n "Copying /boot/initrd-$kernel.img... "
if [ -f /boot/initrd-$kernel.img ]; then
  cp -p /boot/initrd-$kernel.img $BOOTDESTDIR/initrd.img
fi
[ $? = 0 ] || failed=1
[ -n "$verbose" ] && echo "done."

[ -n "$verbose" ] && echo -n "Configuring bootloader... "

[ -f $BOOTDESTDIR/initrd.img ] && INITRDARG="initrd=initrd.img"

if [ $(echo $rootdev | cut -b 6-9) = "loop" ]; then
    rootdev=$(ls -l $rootdev | sed 's/,//' | awk '{ printf("%02x%02x\n", $5, $6); }')
fi

cat > $cfgfile <<EOF
default linux
prompt 1
display boot.msg
timeout 100
label linux
    kernel vmlinuz
    append $INITRDARG $kernelargs root=$rootdev
EOF

[ $? = 0 ] || failed=1

chmod 644 $cfgfile

if [ -f /etc/redhat-release ]; then
    title="$(sed 's/ release.*$//' < /etc/redhat-release)"
else
    title="Red Hat Linux"
fi


cat >> $bootmsg <<EOF

Press <return> (or wait 10 seconds) to boot your $title system from
$rootdev. You may override the default linux kernel parameters by typing
"linux <params>", followed by <return> if you like.

EOF

[ $? = 0 ] || failed=1

[ -n "$verbose" ] && echo "done."

if [ -n "$isoimage" ]; then
    mkisofs \
    -A "Red Hat Linux Boot CD" \
    -V "Red Hat Linux Boot CD" \
    -J -R -T -quiet \
    -o $device \
    -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot \
       -boot-load-size 4 -boot-info-table $MOUNTDIR
    rm -rf $MOUNTDIR
else
    umount $MOUNTDIR
    rmdir $MOUNTDIR
fi

if [ -n "$realdev" ] && [ $failed -eq 0 ]; then
    dd if="$device" of="$realdev" bs=72k 
    rm -f "$device"
fi

if [ $failed -eq 1 ]; then
  exit 1
else
  exit 0
fi