#!/bin/sh

#
#   $Id: si_mkbootserver 2872 2004-09-29 18:36:18Z brianfinley $
#
#   Written by Dann Frazier <daniel_frazier@hp.com>
#

#########################################################################
# The intent of this script is to automate the configuration of a
# linux PXE server, and is written with SystemImager in mind.
# it uses pxelinux and configures it for a kernel/single ramdisk scenario.
#
# it is written as a set of independent tasks so that it can hopefully
# be expanded for other architectures, and other non-SystemImager purposes
#
#########################################################################

INTERACTIVE="yes"
INTERFACE=""
LOCAL_DHCP=""
KERNEL=""
INITRD=""
TFTPDIR=""
PXELINUX=""

program_name=$(basename $0)

usage="\
Usage:  $program_name [-f] [--interface=interface] [--localdhcp=y|n] 
	[--kernel=path] [--initrd=path] [--tftpdir=dir] [--pxelinux=path]"
       
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

TFTPD_PATH=""
TFTP_TEST_FILE_TEXT="all your tftp test file are belong to us"
TFTP_DAEMON=""

CONFIG_DIR="/etc/systemimager"

#SYSLINUX_DEFAULT="\
#DEFAULT kernel
#APPEND vga=extended load_ramdisk=1 prompt_ramdisk=0 initrd=initrd.img root=/dev/ram rw
#DISPLAY message.txt
#PROMPT 1
#TIMEOUT 50"

PXE_CONF="\
#  *******  PXE CONFIGURATION FILE *******
# Any Line starting with a '#\" is treated as a comment line
# and ignored. However, '#' must be the first character on
# a line and no spaces before that are allowed.


# The following entry is the name of the interface on which pxe is going
# to operate. We use this interface to get the ip address automatically.

[Network_Interface_Name]
eth0


# The following entry will be queried if PXE fails to get 
# the IP address automatically through 'ifconfig' like code built-in. This
# is only needed if the above interface name is not present in the system


[OurIpAddress]
#192.215.100.202


# This entry shows the base directory of the mtftpd. All file names/paths
# will be relative to this directory. This is the same name that should 
# be used as the start up argument to the mtftpd daemon.

[Mtftpd_Root_Directory]
/tftpboot


# Set the following entry to 0 if you have a DHCP server running on this 
# system.

[UseDHCPPort]
1


# Set the entry below to zero if you don't want this system to act 
# as a PXE proxyDHCP

[StartProxy]
1


# Set the entry below to zero if you don't want this system to act as a 
# PXE boot server

[startBootService]
1


[MasterProxy]
1


# 0 - broadcast discovery is enabled; 1 - broadcast discovery is disabled

[Discovery_BCast_Disabled]
0


# 0 - multicast discovery is enabled; 1 - multicast discovery is disabled

[Discovery_MCast_Disabled]
0


# Multicast Discovery address. The boot server would listen on this address 
# for multicast boot server packets.

[Discovery_MCast_Addr]
224.0.1.2


# Prompt to display on the user screen
# format of this entry: timeout,<string>

[Prompt]
10,Press F8 to view menu ...


# This entry is set to 1 if the client should accept only responses
# from servers in this list

[Discovery_Server_List_Only]
0


# the format of the discovery_list entry is as follows
# type of the server, # of entries, Ip address of each entry 
# separated by commas

[Discovery_List]
#3,2,192.215.100.49,192.215.100.99
#65535,1,192.215.100.45


# In some systems, the all '1' broadcast address 255.255.255.255 
# won't work as the system will fail with a network unreachable message.
# In those cases, you can use the 'route add -host 255.255.255.255 eth0' 
# command to add a route. Or else, you can define the host portion of the 
# address alone as '1' in the following entry. This entry is not 
# required if your system is set up to transmit
# broadcast packets on 255.255.255.255

[Broadcast_ip_address]
#192.215.100.255


# Architectures supported
# format : <arch-type>,<arch-string>

[PROC_ARCH]
0,X86PC


# Boot server types supported

[Service_Types]
0,BStrap
13,linux-install
# 14,linux-boot


# Menu string that will be displayed on the client screen
# after F8 is pressed.
[X86PC/UNDI/MENU]
0,Local Boot
13,Remote Install Linux
# 14,Remote Boot Linux


# Image file name for Linux install boot server type
# format : <min layer #> <max layer #> <base file name>
[X86PC/UNDI/linux-install/ImageFile_Name]
0
2
linux


# Image file name for Linux boot server type
# format : <min layer #> <max layer #> <base file name>
# [X86PC/UNDI/linux-boot/ImageFile_Name]
# 0
# 2
# linux


# Image file name for BStrap boot server
# format : <min layer #> <max layer #> <base file name>

[X86PC/UNDI/BStrap/ImageFile_Name]
0
0
bstrap


# List of plug-ins. The PXEClientTester is the plug-in that
# validates received packets for PXE compliance. By default, this
# plug-in is DISBALED. Remove the '#\" in front of it, if you want
# packet validation to happen

[Parsers]
# PXEClientTester
PxeParser


[Parsers/PxeParser/MainFunction]
PxeParser


[Parsers/PxeParser/DllPath]
/usr/lib/libpxeParser.so


[Parsers/PXEClientTester/MainFunction]
PXEClientTester


[Parsers/PXEClientTester/DllPath]
/usr/lib/libpxeTester.so


# Even if the PXEClientTester is loaded, you still need to
# turn this flag to '1' for packet validation.

[TestOn]
1


# Directory where the results of the packet validation by PXEClientTester
# will be written to. Under this directory, there will be 
# sub-directories with the last 8 digits of the MAc address of
# each client.

[TestPath]
/tmp


# Option DLL for BStrap

[X86PC/UNDI/BStrap/Vendor_Dll]
/usr/lib/libBstrapOpts.so


# Fill in a NT server name that will be contacted by the client
# to log back in for APitest

[ServerName]
#vviswana-desk2


# Specify whether the above server is in a domain or a workgroup

[IsDomain]
0


# specify the name of the workgroup or domain of the server

[Domain]
starwars


# All debug related stuff here


# If this entry is set to 1, pxe services will write
# more debug info to the system log using syslog()

[DEBUG/PxeServices_DebugOutToWindow_On]
0


# If this entry is set to 1, pxe parser will write
# more debug info to the system log using syslog()

[DEBUG/PxeParsers_DebugOutToWindow_On]
0

# If this entry is set to 1, pxe services will write
# more debug info to the file mentioned
# under the entry [DEBUG/PxeServices_Debug_FileName]

[DEBUG/PxeServices_DebugOutToFile_On]
0


# If this entry is set to 1, pxe parser will write
# more debug info to the file mentioned
# under the entry [DEBUG/PxeParsers_Debug_FileName]

[DEBUG/PxeParsers_DebugOutToFile_On]
0


[DEBUG/PxeServices_Debug_FileName]
/PxeServiceLog.txt


[DEBUG/PxeParsers_Debug_FileName]
/PxeParserLog.txt


[End]"

### BEGIN BACKUP_FILE()
############################################################
# takes the variable $FILE_TO_BACKUP, and renames the file #
# to <$FILE_TO_BACKUP>.<name of this script>.bak.<N>       #
# where <N> is the next number, starting at 0, that does   #
# not conflict with a file that already exists             #
############################################################
backup_file() {
    if [ "$FILE_TO_BACKUP" == "" ]; then
	echo "BUG:  call to backup_file() with FILE_TO_BACKUP not set"
	exit 1
    fi
    
    if [ ! -a "$FILE_TO_BACKUP" ]; then
	echo "$FILE_TO_BACKUP does not already exist, so not backing it up."
	return 0
    fi
    echo "Backing up $FILE_TO_BACKUP..."
    backup_file_i=0
    while /bin/true; do
	if [ ! -a $FILE_TO_BACKUP.$program_name.bak$backup_file_i ]; then
	    echo -n "Moving $FILE_TO_BACKUP to $FILE_TO_BACKUP.$program_name.bak$backup_file_i..."
	    mv $FILE_TO_BACKUP $FILE_TO_BACKUP.$program_name.bak$backup_file_i
	    if [ $? -ne 0 ]; then
		echo "failed."
		return 1
	    fi
	    break
	fi
	backup_file_i=`expr $backup_file_i + 1`
    done
    echo "done."
    return 0
}
### END BACKUP_FILE()

### BEGIN CHECK_TFTPD
##############################
# checks for any tftp server #
##############################
check_tftpd() {
    # check to see if a tftp server is installed
    echo -n "Checking for a tftp server... "
    TFTP_PATH=`which in.tftpd`
    if [ "$TFTP_PATH" == "" ]; then
	echo "failed."
	echo "****************************************************************"
	echo "A tftp server is required, but I couldn't find one in:"
	echo "$PATH."
	echo "You will need to install one."
	echo ""
	echo "I suggest using a tftp server with H. Peter Anvin's patch, or"
	echo "atftpd.  If you're using RedHat 7.0 or higher, the included"
	echo "tftp-server package will do the trick.  For earlier versions"
	echo "of RedHat, you can try using the tftp-hpa package which is"
	echo "available at http://systemimager.org.  For Debian systems"
	echo "more recent than Potato (2.2) you should just be able to"
	echo "apt-get install either tftpd-hpa or atftpd.  For earlier"
	echo "systems you can add a deb-src entry to point to a"
	echo "Debian/unstable mirror, apt-get source one of these packages,"
	echo "and run dpkg-buildpackage to build debs for your system."
	echo "Once you've installed an appropriate tftp server, you can"
	echo "then re-run this script to complete the configuration."
	echo "****************************************************************"
	return 1
    else
	echo "found."
    fi

    # at this point, there should be a tftp server installed
    TFTPD_PATH=`which in.tftpd`
    if [ "$TFTPD_PATH" == "" ]; then
	echo "Still can't find in.tftpd in your PATH.  Try updating your PATH."
	return 1
    fi
}    
### END CHECK_TFTPD

### BEGIN CHECK_TFTPD_HPA
########################################################
# Check to see if the tftp server is hpa's tftp server #
# by looking for the string "hpa" in the binary        #
########################################################
check_tftpd_hpa() {
    echo -n "Checking if tftp server is H. Peter Anvin's tftp server... "
    TFTPD_PATH=`which in.tftpd`
    if [ "$TFTPD_PATH" == "" ]; then
	echo "Couldn't find in.tftpd in your path."
	return 1
    fi
    
    # suggestions for a better test welcome!
    strings $TFTPD_PATH | grep "hpa" 1> /dev/null 2> /dev/null
    if [ $? -eq 0 ]; then
	echo "yup - right on!"
	return 0
    else
	echo "doesn't look like it."
	return 1
    fi
}
### END CHECK_TFTPD_HPA

### BEGIN CHECK_ATFTPD
######################################################
# check to see if in.tftpd is atftp by examining the #
# output of in.tftpd -V                              #
######################################################
check_atftpd() {
    echo -n "Checking if tftp server is atftpd... "
    TFTPD_PATH=`which in.tftpd`
    if [ "$TFTPD_PATH" == "" ]; then
	echo "Couldn't find in.tftpd in your path."
	return 1
    fi

    $TFTPD_PATH -V | grep "atftp" 1> /dev/null 2> /dev/null
    if [ $? -eq 0 ]; then
	echo "yup - right on!"
	return 0
    else
	echo "doesn't look like it."
	return 1
    fi
}
### END CHECK_ATFTPD

##############################################################################
# configures inetd and xinetd for use with hpa's tftp server
##############################################################################

### BEGIN CONFIGURE INETD FOR TFTPD_HPA
configure_inetd_for_tftpd_hpa() {
    if [ "$TFTP_DAEMON" == "tftpd-hpa" ]; then
	inetd_entry="tftp\tdgram\tudp\twait.100\troot\t/usr/sbin/tcpd\tin.tftpd -s -r blksize $TFTPDIR"
	tftp_xinetd="$TFTP_HPA_XINETD"
    elif [ "$TFTP_DAEMON" == "atftpd" ]; then
	inetd_entry="tftp\tdgram\tudp\twait\tnobody\t/usr/sbin/tcpd\t/usr/sbin/in.tftpd --tftpd-timeout 300  --retry-timeout 5 --maxthread 100 --verbose=5 --logfile /var/log/atftpd.log $TFTPDIR"
	tftp_xinetd="$ATFTP_XINETD"
    else
	echo "Unrecognized tftp server, cannot create an inetd entry."
    fi

    ### BEGIN LOOK FOR SUPERSERVER
    echo -n "Checking for a running inetd... "
    inetd_pid=`ps -C inetd | grep inetd | cut -c 0-5`
    if [ "$inetd_pid" == "" ]; then
	echo "Not found."
    else
	echo "$inetd_pid."
    fi
    echo -n "Checking for a running xinetd... "
    xinetd_pid=`ps -C xinetd | grep xinetd | cut -c 0-5`
    if [ "$xinetd_pid" == "" ]; then
	echo "Not found."
    else
	echo "$xinetd_pid."
    fi
    ### END LOOK FOR SUPERSERVER

    echo -n "Looking for update-inetd... "
    which update-inetd 1> /dev/null 2> /dev/null
    if [ $? -eq 0 ]; then
	echo "found."
	# Debian has a tool for this.  Does this work for xinetd?
	echo -n "Updating inetd.conf... "
	update-inetd --remove "^#?tftp.*"
	update-inetd --group BOOT --add "$inetd_entry"
	echo "done."
    else
	echo "not found."
	
	### BEGIN CONFIGURE INETD
	if [ "$inetd_pid" != "" ]; then
	    sed s/"^[[:space:]]*tftp"/"#tftp"/ < /etc/inetd.conf > /tmp/$program_name.inetd.conf
	    mv /etc/inetd.conf /etc/inetd.conf.$program_name.bak
	    mv /tmp/$program_name.inetd.conf /etc/inetd.conf
	    echo -e "$inetd_entry" >> /etc/inetd.conf
	### END CONFIGURE INETD
	    
	### BEGIN CONFIGURE XINETD
	elif [ "$xinetd_pid" != "" ]; then
	    grep "includedir[[:space:]*]/etc/xinetd.d" /etc/xinetd.conf 1> /dev/null 2> /dev/null
	    if [ $? -ne 0 ]; then
		echo "xinetd does not include the /etc/xinetd.d directory"
		echo "you are running an unsupported configuration."
		return 1
	    fi
	    FILE_TO_BACKUP=/etc/xinetd.d/tftp
	    backup_file
	    if [ $? -ne 0 ]; then
		return 1
	    fi

	    echo "${tftp_xinetd}" > /etc/xinetd.d/tftp
	### END CONFIGURE XINETD
	else
	    echo "I couldn't find a running inetd or xinetd."
	    echo "Nothing to configure."
	    return 1
	fi
    fi

    ### BEGIN RELOAD SUPERSERVER
    if [ "$inetd_pid" != "" ]; then
	echo -n "Sending a SIGHUP to inetd (pid $inetd_pid)... "
	kill -HUP $inetd_pid
	if [ $? -ne 0 ]; then
	    echo "failed."
	    return 1
	fi
	echo "done."
    elif [ "$xinetd_pid" != "" ]; then
	echo "Sending SIGUSR2 to xinetd... "
	kill -USR2 $xinetd_pid
	if [ $? -eq 0 ]; then
	    echo "done."
	else
	    echo "failed."
	    return 1
	fi
    else
	echo "No superserver found, so nothing to reload"
    	return 1
    fi
    ### END RELOAD SUPERSERVER
}
### END CONFIGURE INETD FOR TFTPD_HPA

### BEGIN TEST_TFTPD
test_tftpd() {
    echo -n "Looking for a tftp client... "
    TFTP_CLIENT=`which tftp`

    ### BEGIN TFTP CLIENT NOT FOUND
    if [ "$TFTP_CLIENT" == "" ]; then
	echo "in.tftpd not found in your PATH."
	echo ""
	echo "A tftp client is required to test the functionality of your"
	echo "tftp server.  Please install an appropriate tftp client package"
	echo "for your distribution."
	return 1
    fi

    TFTP_CLIENT=`which tftp`
    if [ "$TFTP_CLIENT" == "" ]; then
	echo "I still couldn't find a tftp client in your path."
	return 1
    else
	echo "found."
    fi
    ### END TFTP CLIENT NOT FOUND

    # i'm trying to test tftp by requesting a file from localhost
    # but there's not much point if the loopback interface is down
    echo -n "Checking for loopback interface... "
    ifconfig | grep -e "^lo" 1> /dev/null 2> /dev/null
    if [ $? -ne 0 ]; then
	echo "down."
	echo "I need the loopback interface to be up so I can test tftp, but"
	echo "it appears to be down."
	return 1
    fi
    echo "up."
    
    echo -n "Does tftp server work... "
    # the TFTPDIR variable should have been set to a valid path by now
    if [ "$TFTPDIR" == "" ]; then
	echo "no."
	echo "\"$TFTPDIR\" is not a valid tftp directory."
	return 1
    fi

    TMPFILE=""
    for i in `seq 0 9`; do
	if [ -f "$TFTPDIR/test$i" -o -f "./test$i" ]; then
	    continue
	fi
	TMPFILE="$TFTPDIR/test$i"
    done
    
    if [ "$TMPFILE" == "" ]; then
	echo "couldn't tell."
	echo "Unable to come up with an unused filename"
	return 1
    fi

    echo "$TFTP_TEST_FILE_TEXT" > $TMPFILE
    if [ $? -ne 0 ]; then
	echo "no."
	echo "Unable to write to $TMPFILE"
	return 1
    fi
    
    chmod 644 $TMPFILE
    if [ $? -ne 0 ]; then
	echo "Error: chmod failed."
	rm -f $TMPFILE
	exit 1
    fi
    
    tftp localhost 1> /dev/null 2> /dev/null <<EOF
get `basename $TMPFILE`
EOF
    if [ $? -ne 0 ]; then
	echo "Error: tftp returned a non-zero status"
	rm -f $TMPFILE
	exit 1
    fi
    
    diff "./`basename $TMPFILE`" "$TMPFILE" 1> /dev/null 2> /dev/null
    if [ $? -ne 0 ]; then
	echo "no."
	echo "I couldn't tftp a test file from localhost"
	rm -f $TMPFILE
	return 1
    fi

    echo "yes."
    rm -f $TMPFILE
    rm -f `basename $TMPFILE`
    return 0
}    
### END TEST_TFTPD

install_pxe_daemon() {
    echo -n "Looking for a pxe daemon... "
    pxe_daemon=`which pxe`
    if [ "$pxe_daemon" != "" ]; then
	echo "found."
	return 0
    else
	echo "not found."
	echo "****************************************************************"
	echo "I couldn't find a pxe daemon on your system.  For RedHat"
	echo "systems, you can install the pxe RPM for your release.  For"
	echo "Debian systems, you can try one of the debs i've built from the"
	echo "RedHat package source.  These packages should be available from"
	echo "http://dannf.org/systemimager"
	echo "****************************************************************"
	return 1
    fi
}

# the config file for pxe is pretty awkward.
# you can't go all crazy & start changing the order of things in the file.
# and why can't the key & value be on the same line?
configure_pxe_daemon() {
    FILE_TO_BACKUP=/etc/pxe.conf
    backup_file
    if [ $? -ne 0 ]; then
	return 1
    fi

    echo "${PXE_CONF}" > /etc/pxe.conf

    ### BEGIN edit /etc/pxe.conf
    if [ "$INTERFACE" != "" ]; then
	REPLY=$INTERFACE
    else
	echo -n "What network interface should pxe run on? ([eth0])? "
	read REPLY
    fi
    if [ "$REPLY" = "" ]; then
	interface="eth0"
    else
	interface=$REPLY
    fi

    echo -n "Checking to make sure $interface exists... "
    cut -d ":" -f 1 /proc/net/dev | grep "$interface" 1> /dev/null 2> /dev/null
    if [ $? -eq 0 ]; then
	echo "yeah."
    else
	echo "no."
	return 1
    fi
    
    echo -n "Checking to make sure $interface is up... "
    ifconfig $interface | grep "inet" 1> /dev/null 2> /dev/null
    if [ $? -eq 0 ]; then
	echo "yup."
    else
        echo "nope."
	echo "The pxe daemon won't start if the interface it's using is down."
	return 1
    fi
    
    line=`grep -n "\[Network_Interface_Name\]" /etc/pxe.conf | cut -d ":" -f 1`
    sed -e `expr $line + 1`'c\
'"$interface" < /etc/pxe.conf > /tmp/pxe.conf.$program_name.tmp
    mv /tmp/pxe.conf.$program_name.tmp /etc/pxe.conf

    if [ "$LOCAL_DHCP" != "" ]; then
	REPLY="$LOCAL_DHCP"
    else
	echo -n "Will the DHCP server be running on this machine? ([y]/n)? "
	read REPLY
    fi
    case $REPLY in
	n|N|No|NO ) usedhcpport="1" ;;
	* ) usedhcpport="0" ;;
    esac

    line=`grep -n "\[UseDHCPPort\]" /etc/pxe.conf | cut -d ":" -f 1`
    sed -e `expr $line + 1`'c\
'"$usedhcpport" < /etc/pxe.conf > /tmp/pxe.conf.$program_name.tmp
    mv /tmp/pxe.conf.$program_name.tmp /etc/pxe.conf
    
    ### END edit /etc/pxe.conf

    ### BEGIN restart pxe daemon
    echo "Restarting pxe daemon... "
    if [ -x /etc/init.d/pxe ]; then
	/etc/init.d/pxe stop
	/etc/init.d/pxe start
	echo "done."
    elif [ -x /etc/rc.d/init.d/pxe ]; then
	/etc/rc.d/init.d/pxe stop
	/etc/rc.d/init.d/pxe start
	echo "done."
    else
	echo "failed."
	return 1
    fi

    echo -n "Checking to see if pxe daemon exited silently... "
    if [ "`ps -C pxe | grep pxe`" == "" ]; then
	echo "it did."
	echo "it looks like pxe is misconfigured."
	return 1
    else
	echo "nope - still running :)"
    fi
    ### END restart pxe daemon
}

########################################################
# this function aims to put all the files required by  #
# PXE clients in the right place(s) in TFTPDIR         #
#                                                      #
# i only have access to 2 different PXE clients, and   #
# they do things differently.  The older one uses      #
# Intel Boot Agent (TM) 3.x, the other uses 4.x.       #
# I can't get the older one to work without running    #
# the pxe daemon, and it looks for files in            #
# the $LINUX_INSTALL directory, the other just looks   #
# for files directly under $TFTPDIR.                   #
# The way you can tell which type of client you have   #
# (assuming it's one of these 2 types) is by watching  #
# the console when the client boots.  if it give you   #
# a small menu, offering a choice between a linux      #
# install and a local boot, you have the former.       #
# if you get no such menu, you are probably using      #
# the newer type of client and do not need the pxe     #
# daemon (one less thing.) - it can accept the boot    #
# file option from your DHCP server.                   #
#                                                      #
# this is obviously a lot of hand-waving, because i    #
# really don't know which is abiding to the spec, or   #
# if both abide and a single general config exists     #
# to satisfy both, i just link stuff in both places    #
# (i still want my machine to boot, even if it         #
# violates the spec :)                                 #
#              -dann                                   #
########################################################
pxelinux_cfg() {
    LINUX_INSTALL=$TFTPDIR/X86PC/UNDI/linux-install
    if [ ! -d $LINUX_INSTALL/pxelinux.cfg ]; then
	mkdir -p $LINUX_INSTALL/pxelinux.cfg
    	
	if [ $? -ne 0 ]; then
	    echo "Couldn't create $LINUX_INSTALL"
	    return 1
	fi
    fi
    
    cp -f ${CONFIG_DIR}/pxelinux.cfg/syslinux.cfg.localboot $LINUX_INSTALL/pxelinux.cfg/default
    if [ $? -ne 0 ]; then
	echo "failed."
	return 1
    fi

    cp -f ${CONFIG_DIR}/pxelinux.cfg/message.txt $LINUX_INSTALL/message.txt
    if [ $? -ne 0 ]; then
	echo "failed."
	return 1
    fi
    echo "done."

    if [ -z "$PXELINUX" ]; then
	echo -n "What is the path to the pxelinux bootloader [/usr/lib/syslinux/pxelinux.0]? "
	if [ "$INTERACTIVE" == "no" ]; then
	    REPLY=""
	    echo "Non-interactive mode, assuming default."
	else
	    read REPLY
	fi
	if [ "$REPLY" == "" ]; then
	    PXELINUX="/usr/lib/syslinux/pxelinux.0"
	else
	    PXELINUX=$REPLY
	fi
    fi
    if [ ! -f "$PXELINUX" ]; then
	echo "$PXELINUX does not exist or is not a regular file."
	return 1
    fi	
    if [ ! -f $PXELINUX ]; then
	echo "Couldn't find $PXELINUX"
	return 1
    fi

    ### BEGIN BACKUP EXISTING PXELINUX.BIN
    if [ -a $LINUX_INSTALL/linux.0 ]; then
	if [ "`md5sum $LINUX_INSTALL/linux.0` != \
			`md5sum $PXELINUX`" ]; then
            echo "$LINUX_INSTALL/linux.0 already exists, but doesn't match the pxelinux.0 I want to install."

	    FILE_TO_BACKUP=$LINUX_INSTALL/linux.0
	    backup_file
	    if [ $? -ne 0 ]; then
		return 1
	    fi
	fi
    fi
    ### END BACKUP EXISTING PXELINUX.BIN

    ### BEGIN COPY OVER PXELINUX.BIN
    if [ ! -a $LINUX_INSTALL/linux.0 ]; then
	echo -n "Copying $PXELINUX to $LINUX_INSTALL/linux.0 ... "
	cp -a $PXELINUX $LINUX_INSTALL/linux.0
	if [ $? -ne 0 ]; then
	    echo "failed."
	    return 1
	fi
	echo "done."
    fi
    ### END COPY OVER PXELINUX.BIN
	    
    ### BEGIN BACKUP EXISTING PXELINUX.BIN IN TFTPDIR
    if [ -a $TFTPDIR/pxelinux.bin ]; then
	if [ `md5sum $LINUX_INSTALL/linux.0` != \
		`md5sum $TFTPDIR/pxelinux.bin` ]; then
	    echo "$TFTPDIR/pxelinux.bin already exists, but doesn't match the pxelinux.0 I want to install."
	    FILE_TO_BACKUP=$TFTPDIR/pxelinux.bin
	    backup_file
	    if [ $? -ne 0 ]; then
		return 1
	    fi
	fi
    fi
    ### END BACKUP EXISTING PXELINUX.BIN IN TFTPDIR

    ### BEGIN CREATE PXELINUX.BIN LINK IN TFTPDIR
    if [ ! -a $TFTPDIR/pxelinux.bin ]; then
	echo -n "Linking $TFTPDIR/pxelinux.bin to $LINUX_INSTALL/linux.0 ..."
	ln $LINUX_INSTALL/linux.0 $TFTPDIR/pxelinux.bin
	if [ $? -ne 0 ]; then
	    echo "failed."
	    return 1
	fi
	echo "done."
    fi
    ### END CREATE PXELINUX.BIN LINK IN TFTPDIR

    ### BEGIN PROMPT USER FOR KERNEL
    KERNEL_DEFAULT="/usr/share/systemimager/boot/i386/standard/kernel"
    if [ "$KERNEL" != "" ]; then
	REPLY=$KERNEL
    else
	echo -n "What is the full pathname of the kernel you want to use? [(${KERNEL_DEFAULT})] "
	read REPLY
    fi
    if [ -z $REPLY ]; then
        REPLY=$KERNEL_DEFAULT
    fi
    if [ ! -f "$REPLY" ]; then
	echo "$REPLY doesn't exist, or isn't a regular file."
	return 1
    fi
    ### END PROMPT USER FOR KERNEL

    ### BEGIN BACKUP EXISTING KERNEL
    if [ -a $LINUX_INSTALL/kernel ]; then
	FILE_TO_BACKUP=$LINUX_INSTALL/kernel
	backup_file
	if [ $? -ne 0 ]; then
	    return 1
	fi
    fi
    ### END BACKUP EXISTING KERNEL
    
    ### BEGIN COPY OVER KERNEL
    echo -n "Copying $REPLY to $LINUX_INSTALL/kernel ... "
    cp -a $REPLY $LINUX_INSTALL/kernel
    if [ $? -ne 0 ]; then
	echo "failed."
	return 1
    fi
    echo "done."
    ### END COPY OVER KERNEL
    
    ### BEGIN BACKUP EXISTING KERNEL IN TFTPDIR
    if [ -a $TFTPDIR/kernel ]; then
	if [ "`md5sum $TFTPDIR/kernel`" != \
		"`md5sum $LINUX_INSTALL/kernel`" ]; then
	    FILE_TO_BACKUP=$TFTPDIR/kernel
	    backup_file
	    if [ $? -ne 0 ]; then
		return 1
	    fi
	fi
    fi
    ### END BACKUP EXISTING KERNEL IN TFTPDIR
    
    ### BEGIN CREATE KERNEL LINK IN TFTPDIR
    if [ ! -a $TFTPDIR/kernel ]; then
	echo -n "Linking $TFTPDIR/kernel to $LINUX_INSTALL/kernel ..."
	ln $LINUX_INSTALL/kernel $TFTPDIR/kernel
	if [ $? -ne 0 ]; then
	    echo "failed."
	    return 1
	fi
	echo "done."
    fi
    ### END CREATE KERNEL LINK IN TFTPDIR
    
    ### BEGIN PROMPT USER FOR RAMDISK
    INITRD_DEFAULT="/usr/share/systemimager/boot/i386/standard/initrd.img"
    if [ "$INITRD" != "" ]; then
	REPLY=$INITRD
    else
	echo -n "What is the full pathname of the compressed ramdisk (initrd.img) you want to use? [(${INITRD_DEFAULT})]"
	read REPLY
    fi
    if [ -z $REPLY ]; then
        REPLY=$INITRD_DEFAULT
    fi        
    if [ ! -f $REPLY ]; then
	echo "$REPLY doesn't exist, or isn't a regular file."
	return 1
    fi
    ### END PROMPT USER FOR RAMDISK

    ### BEGIN BACKUP EXISTING RAMDISK
    if [ -a $LINUX_INSTALL/initrd.img ]; then
	FILE_TO_BACKUP=$LINUX_INSTALL/initrd.img
	backup_file
	if [ $? -ne 0 ]; then
	    return 1
	fi
    fi
    ### END BACKUP EXISTING RAMDISK
    
    ### BEGIN COPY OVER RAMDISK
    echo -n "Copying $REPLY to $LINUX_INSTALL/initrd.img ... "
    cp -a $REPLY $LINUX_INSTALL/initrd.img
    if [ $? -ne 0 ]; then
	echo "failed."
	return 1
    fi
    echo "done."
    ### END COPY OVER RAMDISK

    ### BEGIN CHECK EXISTING RAMDISK IN TFTPDIR
    if [ -a $TFTPDIR/initrd.img ]; then
	if [ `md5sum $LINUX_INSTALL/initrd.img` != \
		`md5sum $TFTPDIR/initrd.img` ]; then
	    echo "$TFTPDIR/initrd.img already exists, but doesn't match the initrd.img I want to install."
	    FILE_TO_BACKUP=$TFTPDIR/initrd.img
	    backup_file
	    if [ $? -ne 0 ]; then
		return 1
	    fi
	fi
    fi
    ### END CHECK EXISTING RAMDISK IN TFTPDIR

    ### BEGIN CREATE RAMDISK LINK IN TFTPDIR
    if [ ! -a $TFTPDIR/initrd.img ]; then
	echo -n "Linking $TFTPDIR/initrd.img to $LINUX_INSTALL/initrd.img ..."
	ln $LINUX_INSTALL/initrd.img $TFTPDIR/initrd.img
	if [ $? -ne 0 ]; then
	    echo "failed."
	    return 1
	fi
	echo "done."
    fi
    ### END CREATE RAMDISK LINK IN TFTPDIR

    ### BEGIN COPY PXELINUX.CFG
    if [ -a $TFTPDIR/pxelinux.cfg ]; then
	FILE_TO_BACKUP=$TFTPDIR/pxelinux.cfg
	backup_file
	if [ $? -ne 0 ]; then
	    return 1
	fi
    fi
    echo -n "Copying $LINUX_INSTALL/pxelinux.cfg to $TFTPDIR/pxelinux.cfg..."
    cp -a $LINUX_INSTALL/pxelinux.cfg $TFTPDIR
    ### END COPY PXELINUX.CFG

}    

### BEGIN MAIN        
if [ "`whoami`" != "root" ]; then
    echo "You must be root to run this script, exiting."
    exit 1
fi

# so we can use relative pathnames - hopefully dirname is pretty standard.
cd `dirname $0`
    
while [ $# -gt 0 ]; do
    case "$1" in
	-f )               INTERACTIVE="no" ; shift ;;
        --interface=* )    INTERFACE="`echo \"${1}\" | sed -e 's/^[^=]*=//'`" ; shift ;;
	--localdhcp=* )    LOCAL_DHCP="`echo \"${1}\" | sed -e 's/^[^=]*=//'`" ; shift ;;
	--kernel=* )       KERNEL="`echo \"${1}\" | sed -e 's/^[^=]*=//'`" ; shift ;;
	--initrd=* )       INITRD="`echo \"${1}\" | sed -e 's/^[^=]*=//'`" ; shift ;;
	--tftpdir=* )      TFTPDIR="`echo \"${1}\" | sed -e 's/^[^=]*=//'`" ; shift ;;
	--pxelinux=* )     PXELINUX="`echo \"${1}\" | sed -e 's/^[^=]*=//'`" ; shift ;;
	
	* ) echo "${usage}" 1>&2; exit 1 ;;
    esac
done

echo "This script may modify the following files:"
echo "/etc/services"
echo "/etc/inetd.conf"
echo "/etc/xinetd.d/tftp"
echo "You should already have a kernel and ramdisk to use."
echo -n "Do you wish to continue (y/[n])? "
if [ "$INTERACTIVE" == "no" ]; then
    REPLY="y"
    echo "Non-interactive mode, answering yes."
else
    read REPLY
fi
case $REPLY in
    y|Y|Yes|yes|YES ) echo "Ok, continuing..." ;;
    * ) echo "Cancelled." && exit 1 ;;
esac

if [ "$TFTPDIR" == "" ]; then
    echo -n "Where should tftpd serve files from ([/tftpboot]? "
    if [ "$INTERACTIVE" == "no" ]; then
	REPLY=""
	echo "Non-interactive mode, taking the default."
    else
	read REPLY
    fi
    if [ "$REPLY" == "" ]; then
	TFTPDIR="/tftpboot"
    else
	TFTPDIR=$REPLY
    fi
fi


if [ ! -d $TFTPDIR ]; then
    if [ -a $TFTPDIR ]; then
	echo "$TFTPDIR exists, but isn't a directory, exiting."
	exit 1
    else
	echo -n "$TFTPDIR doesn't exist, should I create it (y/[n])? "
	if [ "$INTERACTIVE" == "no" ]; then
	    REPLY="y"
	    echo "Non-interactive mode, answering yes."
	else
	    read REPLY
	fi
	case $REPLY in
	    y|Y|Yes|yes|YES ) echo -n "Creating $TFTPDIR..." ;;
	    * ) echo "Ok, exiting..." && exit 1 ;;
    	esac
	mkdir -p $TFTPDIR
	if [ $? -ne 0 ]; then
	    echo "mkdir returned an error, exiting..."
	    exit 1
	fi
    fi
fi

check_tftpd
if [ $? -ne 0 ]; then
    exit 1
fi

TFTP_HPA_XINETD="\
# default: off
# description: The tftp server serves files using the trivial file transfer
# 	protocol.  The tftp protocol is often used to boot diskless
#	workstations, download configuration files to network-aware printers,
#	and to start the installation process for some operating systems.
service tftp
{
        socket_type             = dgram
        protocol                = udp
        wait                    = yes
        user                    = root
        server                  = `which in.tftpd`
        server_args             = -s $TFTPDIR -r blksize
        disable                 = no
}"

ATFTP_XINETD="\
# default: off
# description: The tftp server serves files using the trivial file transfer
# 	protocol.  The tftp protocol is often used to boot diskless
#	workstations, download configuration files to network-aware printers,
#	and to start the installation process for some operating systems.
service tftp
{
        socket_type             = dgram
        protocol                = udp
        wait                    = yes
        user                    = root
        server                  = `which in.tftpd`
        server_args             = --tftpd-timeout 300  --retry-timeout 5 --maxthread 100 --verbose=5 --logfile /var/log/atftpd.log $TFTPDIR
        disable                 = no
}"

# check to see if the installed tftpd is one
# of the ones that is known to support options
# necessary for PXE booting.
check_tftpd_hpa
if [ $? -ne 0 ]; then
    check_atftpd
    if [ $? -ne 0 ]; then
	exit 1
    else
	TFTP_DAEMON="atftpd"
    fi
else
    TFTP_DAEMON="tftpd-hpa"
fi

configure_inetd_for_tftpd_hpa
if [ $? -ne 0 ]; then
    echo "Attempt to configure inetd failed."
    exit 1
fi    

test_tftpd
if [ $? -ne 0 ]; then
    echo "tftp server test failed."
    exit 1
fi

install_pxe_daemon
if [ $? -ne 0 ]; then
    echo "pxe daemon installation failed"
    exit 1
fi    

configure_pxe_daemon
if [ $? -ne 0 ]; then
    echo "pxe daemon configuration failed"
    exit 1
fi

pxelinux_cfg
if [ $? -ne 0 ]; then
    echo "pxelinux configuration failed"
    exit 1
fi

echo "Ok, configuration complete."
echo "Once you're DHCP server is configured, you should be all set."
if [ "$(which si_mkdhcpserver)" != "" ]; then
    echo -n "Do you want to run si_mkdhcpserver to configure your DHCP server ([y]/n)? "
    if [ "$INTERACTIVE" == "no" ]; then
	REPLY="n"
	echo "Non-interactive mode, answering no."
    else
	read REPLY
    fi
    case $REPLY in
	n|N|No|NO ) exit 0 ;;
	    * ) si_mkdhcpserver ;;
    esac
fi
