#!/bin/bash
#
#  Copyright (C) 2004 Dell Computer Corporation <john_hull@dell.com>
#
#    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.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# Purpose: This program can be used to quickly create a bootable DOS disk
# with a BIOS flash executable file
#
# Last Update: 2007-12-21
baseDir="/usr/share/biosdisk"
confFile="/etc/biosdisk.conf"
tmpMount="/tmp/biosdisk"
libDir="/var/lib/biosdisk"
tmpPath="/tmp"
curDir=`pwd`
device="/dev/fd0"
blconf="/usr/sbin/blconf"
wget="/usr/bin/wget"
options=""

# Flags
mkDisk=0 # TODO:used?
mkFloppyFlag=0
mkPkgFlag=0
mkImgFlag=1 #TODO: needed?
installFlag=0
pkgInstallFlag=0
imgCompleteFlag=0
forceFlag=1
destSpecifiedFlag=0
file=""

if [ -e "$confFile" ]; then
    source "$confFile"
fi

destination=""
dosDisk="$baseDir/dosdisk.img"
pkgSupported="Rpm, Dpkg"
rpmBaseDir="$libDir/rpm"
dpkgPath=""
dpkgName=""

####################### Functions ########################
function showUsage()
{
    echo $"Usage: $0 [action] [options] /path/fileName[.img|.exe]"
    echo $"  [action]  =  { mkfloppy | mkimage | mkpkg | install | uninstall} "
    echo $"  [options] =  [-o option ] [-d device] [ -k basimage]"
    echo $"               [-i destination] [--install] [--distro=<distro>]"
    echo $"               [--name=<pkg name>] [--version=<pkg version>]"
    echo $"               [--release=<pkg release>] [--bioslog=<bios changelog>]"
    echo $"               [-h|--help]"
}

function makeImage()
{
    # Protect against involuntary overwriting
    if [ -e $destination ] && [ $forceFlag == "0" ]; then
        echo "Warning: $destination already exists! [O]verwrite/[A]bort?"
        read choice
        loop=1
        while [ $loop == 1 ]; do
            case $choice in
               O|o)
                   rm -f $destination
                   loop=0
                   ;;
               A|a)
                   echo "$0 aborted by user"
                   loop=0
                   exit 1
                   ;;
               *)
                   echo "Warning: $destination already exists! [O]verwrite/[A]bort?"
                   read choice
                   ;;
            esac
        done
    fi
   
    set -x 
    mkdir -p $tmpMount
    cp -f $dosDisk $destination
    mount -t vfat $destination $tmpMount -o loop
    cp -f $biosFile $tmpMount
    echo "$biosName $options" > $tmpMount/autoexec.bat
    unix2dos $tmpMount/autoexec.bat > /dev/null 2>&1
    umount $tmpMount
    rm -rf $tmpMount
   
    if ! [ "$uninstallFlag" == 1 ]; then
        if [ "$mkFloppyFlag" == 1 ]; then
            echo "Creating BIOS boot floppy on $device"
            dd if=$destination of=$device
        elif [ "$mkPkgFlag" == 0 ]; then
            echo "Creating BIOS floppy image at $destination"
        fi
    fi
}

function setupPxe()
{
    echo "Not yet supported"
    exit 1

}

function makeDpkg()
{
    # Test if build environment is sufficient/sane
    if [ ! -f /usr/bin/dpkg ]; then
	echo "Error: This cannot be a Debian system, you do not have dpkg installed!"
	exit 1
    fi
    dhStatus=`dpkg -s debhelper | grep "Status"`
    if [ ! "$dhStatus" == 'Status: install ok installed' ]; then
        echo "Error: debhelper does not seem to be installed correctly, please install via dpkg!"
	exit 1
    fi
    if [ -z "$pkgName" ]; then
        pkgName=dellbios
    fi
    if [ -z "$pkgVersion" ]; then
        pkgVersion=`date +%Y%m%d`
    fi
    if [ -z "$pkgRelease" ]; then
        pkgRelease=1
    fi
    if [ -z "$biosChangeLog" ]; then
        biosChangeLog=""
    fi
    # pkgRelease treated as debian revision count
    # current solution imitates a kernel/initrd pair, its suboptimal
    if [ -e $destination ]; then
	destDir=`dirname $destination`
	dpkgPath="$destDir/$pkgName-$pkgVersion"
    else
        dpkgPath="$tmpPath/$pkgName-$pkgVersion"
    fi
    echo "Building Debian package in $dpkgPath ..."
    dpkgName=$pkgName"_"$pkgVersion"-"$pkgRelease"_i386.deb"
    # Redefining $destination, suboptimal
    destination=$dpkgPath"/initrd.img-"$pkgVersion"-"$pkgName
    # exporting variables so that make in debian/rules gets them
    export pkgName pkgVersion pkgRelease dpkgPath biosChangeLog
    if [ -e $dpkgPath ]; then
        rm -rf $dpkgPath
    fi
    mkdir $dpkgPath
    tar -x --bzip2 -f "$baseDir/dpkgfiles.tar.bz2" -C $dpkgPath
    cd $dpkgPath
    makeImage
    debian/rules binary
    cd $curDir
    echo "Debian package created in $dpkgPath"
    if [ "$pkgInstallFlag" == 1 ]; then
	echo "Installing Debian package"
        dpkg --install "$dpkgPath/$dpkgName"
    fi 
    exit 0
}

function install()
{
    local kernel="/boot/memdisk"

    if [ -z $title ]; then
        title=`basename $destination`
    fi

    if [ `dirname $destination` != "/boot" ]; then
        cp -f $destination /boot
        destination=/boot/`basename $destination`
    fi
    $blconf --title=$title --add-kernel=$kernel --add-initrd=$destination
    echo "Copied image to $destination and updated bootloader"

}

function uninstall()
{

    $blconf --remove-image=`basename $destination`
    if [ `dirname $destination` != "/boot" ]; then
        destination=/boot/`dirname $destination`
        rm -f $destination
    fi

}

function makeRpm()
{
    # Create base structure
    mkdir -p $rpmBaseDir
    mkdir -p $rpmBaseDir/BUILD
    mkdir -p $rpmBaseDir/SOURCES
    mkdir -p $rpmBaseDir/SPECS
    mkdir -p $rpmBaseDir/RPMS/noarch
    mkdir -p $rpmBaseDir/SRPMS

    if [ "$distro" == "redhat" ]; then
        specfile="$baseDir/biosdisk-mkrpm-redhat-template.spec"
    else
        specfile="$baseDir/biosdisk-mkrpm-generic-template.spec"
    fi
        
    cp -f $destination $rpmBaseDir/SOURCES
    cp -f $specfile $rpmBaseDir/SPECS

    if [ -z "$pkgName" ]; then
        pkgName=bios
    fi
    if [ -z "$pkgVersion" ]; then
        pkgVersion=$fileName
    fi
    if [ -z "$pkgRelease" ]; then
        pkgRelease=1
    fi

    rpmbuild --define "_topdir $rpmBaseDir" --define "name $pkgName" --define "version $pkgVersion" --define "release $pkgRelease" --define "destination $destination" -ba $rpmBaseDir/SPECS/`basename $specfile` >/dev/null 2>&1

    if [ "$?" -eq 0 ]; then
        echo $""
        echo $"Created $pkgName-$pkgVersion-$pkgRelease.noarch.rpm in $rpmBaseDir/RPMS/noarch/"
        echo $""
        echo $"biosdisk: mkrpm Completed."
    else
        echo $"Error: There was a problem creating your rpm."
        exit 7
    fi

    if [ "$destSpecifiedFlag" == 0 ]; then
        rm -f $destination
    fi

    if [ "$pkgInstallFlag" == 1 ]; then
        rpm -ivh $rpmBaseDir/RPMS/noarch/$pkgName-$pkgVersion-$pkgRelease.noarch.rpm
    fi 
}

# see if we can figure out which distro we're running on
# only rudimentary check for Debian, further checks are in makeDpkg
function findDistro()
{
    if [ -f /etc/mandrake-release ] || [ "$distro" == "mandrake" ]; then
        distro=mandrake
        [ -z $pkgType ] && pkgType=rpm
    elif [ -f /etc/fedora-release ] || [ -f /etc/redhat-release ] || [ "$distro" == "redhat" ] ; then
        distro=redhat
        [ -z $pkgType ] && pkgType=rpm
    elif [ -f /etc/SuSE-release ] || [ -f /etc/SuSEconfig ] || [ "$distro" == "suse" ] ; then
        distro=suse
        [ -z $pkgType ] && pkgType=rpm
    elif [ -f /etc/gentoo-release ] || [ "$distro" == "gentoo" ] ; then
        distro=gentoo
        [ -z $pkgType ] && pkgType=emerge
    elif [ -f /etc/debian_version ] || [ "$distro" == "debian" ] ; then
        distro=debian
        [ -z $pkgType ] && pkgType=deb
    else
        if [ -z $pkgType ]; then
            echo "Linux distribution unknown. Please specify the package type with the --pkgtype option on the command line"
             exit 1
        fi
    fi
}

###################### Main #################################

if [ `id -u` != 0 ]; then
    echo "Error: You must run $0 as root"
    exit 0
fi

if [ $# -eq 0 ]; then
    showUsage
    exit 1
fi   

eval last=\${$#}
eval sLast=\$`expr $# - 1`
# Catches incomplete switches
case $sLast in
    -[a-z])
        echo "Error: You do not seem to have specified a BiosExe"
        showUsage
        exit 1
        ;;

esac


# find biosdisk action
case $1 in
    mkfloppy|mkFloppy)
        mkImgFlag=1
        mkFloppyFlag=1
        ;;
    mkimage|mkImage)
	mkImgFlag=1
        ;;
    mkpkg|mkPkg)
        mkImgFlag=1
        mkPkgFlag=1
        ;;
    install)
        mkImgFlag=1
        installFlag=1
        ;;
    uninstall)
        uninstallFlag=1
        ;;
    *)
        echo "Error: biosdisk action incorrect or not specified"
        showUsage
        exit 2
        ;;
esac
shift

# Work through options and act accordingly
while [ $# -gt 0 ]; do
    if [ "$1" -a "$2" ]; then
        case $1 in
            -o)
                options="$options $2"
                shift
                ;;
            -d)
                device=$2
                shift
                ;;
            -i) 
                destination=$2
                destSpecifiedFlag=1
                shift
                ;;
            -k)
                dosDisk=$2
                shift
                ;;
            --install) 
                pkgInstallFlag=1
                ;;
            --distro*)
                if echo $1 | grep '=' >/dev/null ; then
                    distro=`echo $1 | sed 's/^.*=//'`
                else
                    distro="$2"
                    shift
                fi
                ;;
            --name*)
                if echo $1 | grep '=' >/dev/null ; then
                    pkgName=`echo $1 | sed 's/^.*=//'`
                else
                    pkgName="$2"
                    shift
                fi
                ;;
            --version*)
                if echo $1 | grep '=' >/dev/null ; then
                    pkgVersion=`echo $1 | sed 's/^.*=//'`
                else
                    pkgVersion="$2"
                    shift
                fi
                ;;
            --release*)
                if echo $1 | grep '=' >/dev/null ; then
                    pkgRelease=`echo $1 | sed 's/^.*=//'`
                else
                    pkgRelease="$2"
                    shift
                fi
                ;;
            --pkgtype*)
                if echo $1 | grep '=' >/dev/null ; then
                    pkgType=`echo $1 | sed 's/^.*=//'`
                else
                    pkgType="$2"
                    shift
                fi
                ;;
            --title*)
                if echo $1 | grep '=' >/dev/null ; then
                    title=`echo $1 | sed 's/^.*=//'`
                else
                    title="$2"
                    shift
                fi
                ;;
            --bioslog*)
                if echo $1 | grep '=' >/dev/null ; then
                    biosChangeLog=`echo $1 | sed 's/^.*=//'`
                else
                    biosChangeLog="$2"
                    shift
                fi
                ;;
            *)
                echo "Error: $0 does not take \"$1 $2\" as an option"
                showUsage
                exit 1
		;;
        esac
    elif [ "$1" -a -z"$2" ]; then
        case $1 in
            -h|--help)
                showUsage
                exit 1
                ;;
            *)
             # Testing for validity of last argument which should be raw bios or image file
             # If we're here but not on the last argument, the user wrote gibberish

               if [ $last == $1 ]; then
                    if [ ! -f $1 ] && ! [ `echo $1 | grep -c "^[fhFH][tT][Tt]*[pP]"` -eq 1 ]; then
                        echo "Error: \"$1\" treated as a file, but its not useable/nonexistent"
                        showUsage
                        exit 1
                    else
                        #If file is url, then get it
                        if [ `echo $1 | grep -c "^[fhFH][tT][Tt]*[pP]"` -eq 1 ]; then
                            file=$libDir/`basename $1`
			    $wget -O $file $1
                            if ! [ -f $file ]; then
                                echo "Error: could not download file!"
                                exit 1
                            fi
                        else
                            file=$1
                        fi
			# In case the download did not work (timeout, programme not found)

			if [ ! -f $file ]; then
			    echo "Error: Cannot find/use $file"
			    exit 1
			fi
                        fileName=`basename $file | cut -d. -f1`
                        fileExt=`basename $file | cut -d. -f2`                 
                        case $fileExt in
                            img|IMG)
                                imgCompleteFlag=1
                                destSpecifiedFlag=1
                                destination=$file
                                ;;
                            exe|EXE)
                                biosPath=`dirname $file`
                                biosFile=$file
                                biosName=`basename $file`
                                ;;
                            *)
                                echo "Error: $file must end in .img or .exe"
                                showUsage
                                exit 1
                                ;;
                            esac 
                    fi
                else
                    echo "Error: $0 does not take \"$1\" as an option"
                    showUsage
                    exit 1
                fi
               ;;
        esac
    fi
    shift    
done

if [ -z $file ]; then
    echo "Error: must enter filename"
    showUsage
    exit 1
fi

if [ -z "$destination" ]; then
    destination=$tmpPath/$fileName.img
fi

if [ "$uninstallFlag" == 1 ]; then
    uninstall
fi 

if [ "$mkImgFlag" == 1 ] && [ "$imgCompleteFlag" == 0 ]; then
    makeImage
fi

if [ "$installFlag" == 1 ]; then
    install
fi

if [ "$pkgInstallFlag" == 1 ]; then
    if [ -z $distro ]; then
        findDistro
    fi
    if [ $pkgType != "deb" ]; then
    install
    else
    	echo "Error: Automatic installs are not supported under $distro"
        exit 2
    fi
fi

if [ "$mkPkgFlag"  == 1 ]; then
    if [ -z "$distro" ] || [ -z "$pkgType" ]; then
        findDistro
    fi

    case $pkgType in
        rpm)
            makeRpm
            ;;
        deb)
            makeDpkg
            ;;
        *)
            echo "Error: $pkgType not supported with mkpkg. Supported package types are: $pkgSupported"
            exit 1
            ;;
    esac    
fi


