#! /bin/sh
#
# This script installs a network driver, including the MD5 checksum
#
# $Id: instdrv.in,v 1.6 2005/02/27 20:27:54 gkminix Exp $
#


#
############################################################################
#
#  Prepare default values and file names
#
############################################################################
#


#
# Set default file names
#
DEFAULT_MD5SUMS="MD5SUMS"
DEFAULT_MD5PROG="nbmd5"


#
# Set allowed network driver types
#
ALLOWED_TYPES="pktdrvr ndis2 undi"


#
# Set default network driver directory
#
if [ "x$NETBOOT_DATA" = "x" ]; then
	NETBOOT_DATA="/usr/share/netboot"
fi
if [ -d "$NETBOOT_DATA" ] && [ "x$NETDRVDIR" = "x" ]; then
	NETDRVDIR="${NETBOOT_DATA}/netdrvr"
fi


#
# Set default utilities directory
#
if [ "x$NETBOOT_LIB" = "x" ]; then
	NETBOOT_LIB="/usr/lib/netboot"
fi
UTILDIR="/usr/lib/netboot/utils"
if [ ! -d "$UTILDIR" ]; then
	UTILDIR="${NETBOOT_LIB}/utils"
fi


#
# Set temporary file names
#
if [ "x$TEMP" = "x" ]; then
	TEMP="/tmp"
fi
TMPMD5="${TEMP}/MD5SUMS.$$"
TMPSRC="${TEMP}/srcfiles.$$"




#
############################################################################
#
#  Check for some shell variants
#
############################################################################
#


#
# Make zsh Bourne-compatible
#
if [ -n "$ZSH_VERSION" ]; then
	emulate sh
	NULLCMD=":"
fi


#
# Make bash POSIX-compatible
#
if [ -n "$BASH_VERSION" ]; then
	set -o posix
fi




#
############################################################################
#
#  Process command line options
#
############################################################################
#


#
# Parse command line options. Note that we should not use $@ here
# because it is non-portable. Also, using shift in a while loop is
# not portable. Also dont check the OPTION variable with -z or -n
# because this might confuse certain shells if this variable really
# contains an option.
#
ERROR=""
OPTION=""
VERBOSE=0
for arg
do
	if [ "x$OPTION" = "x" ]; then
		case $arg in
			-t | -n | -m | -d | -s)
				OPTION="$arg"
				;;
			-u)
				UPDATE="TRUE"
				;;
			-r)
				REBUILD="TRUE"
				;;
			-v)
				VERBOSE=`expr $VERBOSE + 1`
				;;
			-x)
				DEBUG="TRUE"
				;;
			*)
				ERROR="TRUE"
				;;
		esac
	else
		case $OPTION in
			-t)
				DRVTYPE="$arg"
				;;
			-n)
				NETDRVDIR="$arg"
				;;
			-m)
				MD5SUMS="$arg"
				;;
			-d)
				if [ -z "$SRCFILES" ]; then
					SRCFILES="$arg"
				else
					SRCFILES="$SRCFILES $arg"
				fi
				;;
			-s)
				SUBDIR="$arg"
				;;
			*)
				ERROR="TRUE"
				;;
		esac
		OPTION=""
	fi
	test "$ERROR" != "TRUE" || break
done
test "x$OPTION" = "x" || ERROR="TRUE"


#
# Usage information
#
if [ "$ERROR" = "TRUE" ]; then
	cat >&2 <<EOF
Usage: $0 [options]

Install a network driver binary for use by makerom

Options:
   -t <type>     Driver type, any of: pktdrvr, ndis2, undi
   -n <dir>      Name of network driver installation directory
   -s <dir>      Name of network driver installation subdirectory
   -m <file>     Name of MD5 checksum file
   -d <file>     Name of source network driver file
   -u            Update the MD5 checksum file without installation
   -r            Rebuild MD5 checksum file
   -v            Verbose operation
   -x            Debugging

EOF

	exit 1
fi


#
# Check for proper command line options
#
NETDRVDIR=`echo "$NETDRVDIR" | sed 's,/$,,'`
if [ -z "$NETDRVDIR" ] || [ ! -d "$NETDRVDIR" ]; then
	echo "$0: missing or invalid network driver installation directory" >&2
	exit 1
fi

if [ "$REBUILD" = "TRUE" ]; then
	if [ -n "$DRVTYPE" ] || [ -n "$SRCFILES" ] || \
	   [ -n "$SUBDIR" ] || [ -n "$UPDATE" ]; then
		echo "$0: options -u, -t, -d and -s not allowed with -r" >&2
		exit 1
	fi
	UPDATE="TRUE"
else
	# Check for correct driver type
	if [ -z "$DRVTYPE" ]; then
		echo "$0: missing network driver type" >&2
		exit 1
	fi
	FOUND_TYPE="FALSE"
	for i in $ALLOWED_TYPES
	do
		if [ "$DRVTYPE" = "$i" ]; then
			FOUND_TYPE="TRUE"
			break
		fi
	done
	if [ "$FOUND_TYPE" != "TRUE" ]; then
		echo "$0: invalid network driver type" >&2
		exit 1
	fi

	# Check for network driver source file name
	if [ -z "$SRCFILES" ]; then
		# This is actually not an error, but rather a warning
		if [ "$VERBOSE" -gt 1 ]; then
			echo "$0: missing source file names, nothing to install" >&2
		fi
		exit 0
	fi
	SRCFILES=`echo "$SRCFILES" | sed 's/[:]/ /g'`
	for i in $SRCFILES
	do
		if [ ! -r "$i" ]; then
			echo "$0: unable to read $i" >&2
			exit 1
		fi
	done
fi


#
# Determine name of MD5 checksum file
#
test -n "$MD5SUMS" || MD5SUMS="$DEFAULT_MD5SUMS"
case $MD5SUMS in
	/*)
		# Absolute path name
		;;
	*)
		MD5SUMS="${NETDRVDIR}/${MD5SUMS}"
		;;
esac


#
# Let the user now what we are going to do
#
if [ "$VERBOSE" -gt 1 ]; then
	echo "Netboot network driver installation program"
	echo ""
	echo "Network driver base directory:    $NETDRVDIR"
	echo "MD5 checksum file:                $MD5SUMS"
	echo ""
fi


#
# Remove temporary files if necessary
#
if [ "$DEBUG" != "TRUE" ]; then
	trap "rm -f $TMPMD5 $TMPSRC" 0
fi




#
############################################################################
#
#  Check for some required programs
#
############################################################################
#


#
# Check for MD5 checksum program
#
test -n "$MD5PROG" || MD5PROG="$DEFAULT_MD5PROG"
case $MD5PROG in
	*/libtool*)
		# It's OK when calling MD5PROG through libtool
		;;
	/*)
		# Absolute path name
		if [ ! -f "$MD5PROG" ]; then
			MD5PROG=""
		fi
		;;
	*)
		# Relative path name
		MD5TMP="$MD5PROG"
		MD5PROG=""
		PATHNAMES=`echo "${UTILDIR}:${PATH}" | sed 's/:/ /g'`
		for i in $PATHNAMES; do
			if [ -f $i/$MD5TMP ]; then
				MD5PROG="$i/$MD5TMP"
				break
			fi
		done
		;;
esac
if [ -z "$MD5PROG" ]; then
	echo "$0: missing MD5 checksum program" >&2
	exit 1
fi


#
# Check for install program
#
if [ "$UPDATE" != "TRUE" ] && [ "$REBUILD" != "TRUE" ]; then
	if [ -z "$INSTALL" ]; then
		for i in "/etc/install" \
				"/usr/sbin/install" \
				"/usr/etc/install" \
				"/sbin/install" \
				"/bin/ginstall" \
				"/bin/install" \
				"/usr/bin/ginstall" \
				"/usr/bin/install" \
				"/usr/bin/installbsd" \
				"/usr/afsws/bin/install" \
				"/usr/ucb/install"; do
			if [ -f $i ]; then
				INSTALL="$i"
				break
			fi
		done
	fi
	if [ -z "$INSTALL" ]; then
		echo "$0: missing install program" >&2
		exit 1
	fi
	INSTPROG="${INSTALL}"
else
	INSTPROG=":"
fi



#
############################################################################
#
#  Determine base directory name for all driver files
#
############################################################################
#


#
# The file names in the MD5 checksum file are relative to the directory
# in which the checksum file is located. If the MD5 checksum file is not
# located in the network driver directory, all file names in the checksum
# file have to be absolute.
#
# This is a portable "dirname"
md5dir=`echo "X$MD5SUMS" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
				     /^X\(\/\/\)[^/].*/{ s//\1/; q; }
				     /^X\(\/\/\)$/{ s//\1/; q; }
				     /^X\(\/\).*/{ s//\1/; q; }
				     s/.*/./; q'`

if [ "$md5dir" = "$NETDRVDIR" ]; then
	MAINDIR=""
else
	MAINDIR="${NETDRVDIR}/"
fi



#
############################################################################
#
#  Generate the list of files to process
#
############################################################################
#


#
# Scan through the list of source files and generate the output list
# file. This temporary file has the following syntax:
#
# <directory name as it appears in MD5SUMS file> <source file name>
#
# Each line is for one file
#
if [ "$REBUILD" = "TRUE" ]; then

	# For the rebuild option, we scan for all files already installed
	# in the network driver directory, and seperate the path names

	for SUBDIR in $ALLOWED_TYPES
	do
		DRVDIR="${NETDRVDIR}/${SUBDIR}"
		if [ -d "$DRVDIR" ]; then
			find $DRVDIR -type f | while read i
			do
				echo "${MAINDIR}${SUBDIR} ${i}" >&5
			done
		fi
	done 5>$TMPSRC

else

	# When installing or updating a driver file, we scan through the
	# list of source files given.

	for i in $SRCFILES
	do
		if [ -z "$SUBDIR" ]; then
			echo "${MAINDIR}${DRVTYPE} ${i}" >&5
		else
			echo "${MAINDIR}${DRVTYPE}/${SUBDIR} ${i}" >&5
		fi
	done 5>$TMPSRC

fi




#
############################################################################
#
#  Install the driver files into the destination directory
#
############################################################################
#


#
# Create a new checksum file and write a standard header
#
echo "# netboot network driver MD5 checksum file" >$TMPMD5


#
# Read the source file list and install all source files. Only install a
# file if its not already installed and entered into the MD5 checksum
# database.
#
while read dname sname
do
	# This is a portable "basename"
	fname=`echo "X/$sname" | \
			sed '/.*/y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/;
			     /^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
			     /^X\/\(\/\/\)$/{ s//\1/; q; }
			     /^X\/\(\/\).*/{ s//\1/; q; }
			     s/.*/./; q'`

	# Determine the MD5 checksum of the driver file, and check if it
	# has already been installed according to the old MD5 checksum
	# file. However, the newly computed MD5 checksum gets always
	# written into the new database file.

	DOINSTALL="FALSE"
	if [ -r "$sname" ]; then
		MD5=`$MD5PROG -b $sname | sed 's/[ \t].*$//'`
		if [ "$UPDATE" != "TRUE" ] && [ "$REBUILD" != "TRUE" ]; then
			if [ ! -f "${NETDRVDIR}/${dname}/${fname}" ] || \
			   [ ! -r "$MD5SUMS" ]; then
				DOINSTALL="TRUE"
			else
				if grep "^${MD5}[ \t]*[ *]${dname}/${fname}\$" \
						$MD5SUMS >/dev/null; then
					DOINSTALL="FALSE"
				else
					DOINSTALL="TRUE"
				fi
			fi
		fi
		echo "${MD5} *${dname}/${fname}" >&5
	fi

	# If the file has not already been installed, and we are not just
	# updating the database, we can now install the driver file into
	# its final destination.

	if [ "$DOINSTALL" = "TRUE" ]; then
		DESTDIR="${NETDRVDIR}/${dname}"
		if [ "$VERBOSE" -gt 0 ]; then
			echo "Installing $sname into $DESTDIR"
		fi
		if [ ! -d "$DESTDIR" ]; then
			if [ "$DEBUG" = "TRUE" ]; then
				echo "$INSTPROG -d $DESTDIR"
			else
				$INSTPROG -d $DESTDIR
			fi
		fi
		if [ "$DEBUG" = "TRUE" ]; then
			echo "$INSTPROG -m 644 $sname $DESTDIR/$fname"
		else
			$INSTPROG -m 644 $sname $DESTDIR/$fname
		fi
	fi
done <$TMPSRC 5>>$TMPMD5



#
############################################################################
#
#  Install the new MD5 checksum file
#
############################################################################
#


#
# Scan through old checksum file and find all entries which have not been
# changed so far. These have to be copied into the new file. However, this
# has only to be done if we are not rebuilding the database.
#
if [ "$REBUILD" != "TRUE" ] && [ -r "$MD5SUMS" ]; then
	while read line
	do
		fpath=`echo "$line" | sed 's/[#].*$//;s/^.*[ \t][ *]//'`
		if [ -n "$fpath" ]; then

			# This is a portable "basename"
			fname=`echo "X/$fpath" | \
				sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
				     /^X\/\(\/\/\)$/{ s//\1/; q; }
				     /^X\/\(\/\).*/{ s//\1/; q; }
				     s/.*/./; q'`

			# This is a portable "dirname"
			fdir=`echo "X$fpath" | \
				sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
				     /^X\(\/\/\)[^/].*/{ s//\1/; q; }
				     /^X\(\/\/\)$/{ s//\1/; q; }
				     /^X\(\/\).*/{ s//\1/; q; }
				     s/.*/./; q'`

			# Check if file does not exist in old database
			if grep -i "^$fdir .*$fname\$" $TMPSRC >/dev/null; then
				:
			else
				echo "$line" >&5
			fi
		fi
	done <$MD5SUMS 5>>$TMPMD5
fi


#
# Finally install the new MD5 checksum database file
#
if [ "$VERBOSE" -gt 0 ]; then
	echo "Updating MD5 checksum database file $MD5SUMS"
fi
if [ "$DEBUG" = "TRUE" ]; then
	echo "rm -f $MD5SUMS"
	echo "cp $TMPMD5 $MD5SUMS"
else
	rm -f $MD5SUMS
	cp $TMPMD5 $MD5SUMS
fi

exit 0

