#!/bin/sh
# Script which performs updating services
############################################################################

PROGDIR="/usr/local/share/pcbsd/pc-updatemanager" ; export PROGDIR

# Set the pub openssl key
SKEY="${PROGDIR}/conf/security.key" ; export SKEY

# Directory to store downloaded updates
DOWNLOADDIR="/usr/local/tmp"

# Get the system version we are checking for updates to
SYSVER="`pbreg get /PC-BSD/Version`" ; export SYSVER

# Set the config location
UPDATECONF="${PROGDIR}/conf/sysupdate.conf"

# Set the system arch type
ARCH=`uname -m`

# Default pcbsd.conf file
PCBSD_ETCCONF="/usr/local/etc/pcbsd.conf"

# Patchset Data
PATCHSERVER="`cat ${UPDATECONF} | grep '^UPDATESERVER:' | cut -d ' ' -f 2`"
PATCHSET="`cat ${UPDATECONF} | grep '^PATCHSET:' | cut -d ' ' -f 2`"
PATCHFILE="patch-${PATCHSET}-${SYSVER}-${ARCH}.tgz"
PATCHURL="${PATCHSERVER}/${PATCHFILE}"
PATCHTMPDIR=`mktemp -d /tmp/.sysupdateXXXXXX`
PATCHTMPFILE="${PATCHTMPDIR}/sysupdate-${SYSVER}.tgz"

MUSTAGEDIR="${DOWNLOADDIR}/update-stagedir"

# Enable ftp passive mode for file transfers
FTP_PASSIVE_MODE="YES" ; export FTP_PASSIVE_MODE

if [ ! -d "${DOWNLOADDIR}" ]; then mkdir -p ${DOWNLOADDIR}; fi

# Set the mirror URL
MIRRORURL="`cat ${PCBSD_ETCCONF} | grep 'PCBSD_MIRROR: ' | sed 's|PCBSD_MIRROR: ||g'`"

# Trigger File for Tray Application
TRIGGERFILE="/tmp/.sysupdatetraytrigger"
rm ${TRIGGERFILE} >/dev/null 2>/dev/null

DBDIR="/var/db/pc-updatemanager"
if [ `id -u` != "0" ] ; then
	AVAILDIR=`mktemp -d /tmp/.sysavailXXXXXX`
else
	AVAILDIR="${DBDIR}/available"
fi
INSDIR="${DBDIR}/installed"
IGNDIR="${DBDIR}/ignored"


######################################################################
# Done with config values
######################################################################

show_usage() {
        echo "$0 - Usage
----
  check 		- Check for online updates
  install <tag>,<tag2> 	- Install tagged updates
"	

	exit 1
}

do_check() {

	# Now fetch the update file
	fetch -a -o "${PATCHTMPFILE}" "${PATCHURL}" >/dev/null 2>/dev/null 
	if [ "$?" = "0" ]
	then
	  # If we have new update-data file, extract it
 	  cd ${AVAILDIR}/${SYSVER}

	  # Remove old .upd data files
  	  rm * >/dev/null 2>/dev/null

  	  # Extract the patch data 
  	  tar xvzf ${PATCHTMPFILE} >/dev/null 2>/dev/null

  	  # Remove patchset data, done with it for now
  	  rm -f ${PATCHTMPFILE}
          rm -rf ${PATCHTMPDIR} 
	else
		# If not root, cleanup tmp AVAILDIR
		if [ `id -u` != "0" ] ; then rm -rf "${AVAILDIR}" ; fi

		is_net_up
		if [ $? -eq 0 ] ; then 
			echo "No updates available for $SYSVER!" ; exit 0 
		else
			exit_err "Could not contact update server!"
		fi
	fi

	# Setup our variable, we have no patches so far
	PATCHFOUND="0" 

	# CD to the patch directory for this version
	cd "${AVAILDIR}/${SYSVER}"

	# Check if we have a major version to update
	if [ -e "major-update" ] ; then
	  openssl dgst -sha1 -verify ${SKEY} \
	  	-signature major-update.sha1 \
              	major-update >/dev/null 2>/dev/null
	  if [ $? -eq 0 ] ; then
	    echo "The following updates are available:"
	    echo "------------------------------------"
	    pVer=`cat major-update | grep "^Version:" | sed 's|Version: ||g'`
	    pDate=`cat major-update | grep "^Date:" | sed 's|Date: ||g'`
	    pDet=`cat major-update | grep "^DetailsURL:" | sed 's|DetailsURL: ||g'`
	    pTag="release-${pVer}"
	    PATCHFOUND="`expr ${PATCHFOUND} + 1`" 
	    echo "NAME: System Update to ${pVer}" 
	    echo "TYPE: SYSUPDATE" 
	    echo "VERSION: ${pVer}" 
	    echo "DATE: ${pDate}" 
	    echo "TAG: ${pTag}" 
  	    echo "DETAILS: ${pDet}" 
  	    echo ""
  	    echo "To install this update run \"${0} install ${pTag}\""
  	    echo ""
	  fi
	fi


	# Now check for package updates
	if [ -e "base-ports.tlz" ] ; then
	  openssl dgst -sha1 -verify ${SKEY} \
	  	-signature base-ports.tlz.sha1 \
              	base-ports.tlz >/dev/null 2>/dev/null
	  if [ $? -eq 0 ]; then
	    rm -rf base-ports
	    tar xvJf base-ports.tlz >/dev/null 2>/dev/null

	    # If we have a index, check installed pkgs for updates
	    if [ -e "base-ports/master-pkg-index" ] ; then
	      fPkgUp=0

	      # Checkout the installed pkgs and compare to master list
	      ls /var/db/pkg > /tmp/.pkgList.$$
	      cat base-ports/master-pkg-index | cut -d ":" -f 1-2 | sed 's|:|-|g' > /tmp/.pkgList2.$$
	      diff /tmp/.pkgList.$$ /tmp/.pkgList2.$$ | grep '^<' | sed 's|< ||g' > /tmp/.dList.$$
	      rm /tmp/.pkgList.$$
	      rm /tmp/.pkgList2.$$
	      while read pLine
	      do
		pName=`echo $pLine | rev | cut -d "-" -f 2-25 | rev`
		pVer=`echo $pLine | rev | cut -d "-" -f 1 | rev`
		
	 	# Make sure this version isn't in our index
		grep "^${pName}:${pVer}" base-ports/master-pkg-index >/dev/null 2>/dev/null
		if [ $? -eq 0 ] ; then continue ; fi

	        # Get the info from master-pkg-index
		iLine=`grep "^${pName}:" base-ports/master-pkg-index`
		if [ -z "$iLine" ] ; then continue ; fi


	        iVer="`echo $iLine | cut -d ':' -f 2`"
	        iSiz="`echo $iLine | cut -d ':' -f 3`"
	        iFile="`echo $iLine | cut -d ':' -f 4`"

	 	# Is this version different?
		if [ "$pVer" = "$iVer" ] ; then continue ; fi

		if [ $PATCHFOUND -eq 0 ] ; then
		  echo "The following updates are available:"
		  echo "------------------------------------"
		fi
		if [ $fPkgUp -eq 0 ] ; then 
		  echo "The following package updates are available:"
	          echo "NAME: Package Updates" 
	          echo "TYPE: PACKAGE" 
		  fPkgUp=1
		fi
	        # Display the pkg update data
		echo "PKGUPDATE: ${pName} ${pVer} -> ${iVer}"
		echo "PKGUPDATEKB: ${iSiz}"
		echo "PKGUPDATEFILE: ${iFile}"
	      done < /tmp/.dList.$$
	      rm /tmp/.dList.$$

	      # Display command to use for pkg-updating
	      if [ $fPkgUp -eq 1 ] ; then 
		echo " "
		echo "To install these package updates run \"${0} install pkg-updates\""
		echo " "
	      fi
	    fi
          fi
	fi

	echo ""

	# Now check which stand-alone updates are available
	for i in `ls *.upd 2>/dev/null`
	do
   	  if [ ! -e "${INSDIR}/${SYSVER}/${i}" ]
   	  then
      	      # Now lets check if this .upd file is valid via the sha1 file
	      openssl dgst -sha1 -verify ${SKEY} \
	  	-signature ${i}.sha1 \
              	${i} >/dev/null 2>/dev/null
	      if [ $? -eq 0 ] ; then
		if [ $PATCHFOUND -eq 0 ] ; then
		  echo "The following updates are available:"
		  echo "------------------------------------"
		fi
	        PATCHFOUND="`expr ${PATCHFOUND} + 1`" 
		pName=`cat ${i} | grep "^Name:" | sed 's|Name: ||g'`
		pDate=`cat ${i} | grep "^Date:" | sed 's|Date: ||g'`
		pSize=`cat ${i} | grep "^Size:" | sed 's|Size: ||g'`
		pSA=`cat ${i} | grep "^StandAlone:" | sed 's|StandAlone: ||g'`
		pRR=`cat ${i} | grep "^RequiresReboot:" | sed 's|RequiresReboot: ||g'`
		pDet=`cat ${i} | grep "^DetailsURL:" | sed 's|DetailsURL: ||g'`
		pTag=`echo ${i} | sed 's|\.upd||g'`
		echo "NAME: ${pName}" 
	        echo "TYPE: PATCH" 
		echo "DATE: ${pDate}" 
	        echo "TAG: ${pTag}"
		echo "SIZE: ${pSize}" 
		echo "STANDALONE: ${pSA}" 
		echo "REQUIRESREBOOT: ${pRR}" 
		echo "DETAILS: ${pDet}" 
		echo " "
		echo "To install this update run \"${0} install ${pTag}\""
		echo " "
      	      fi
   	  fi
	done 

	# If no patches
	if [ "${PATCHFOUND}" = "0" ]
	then 
	  # No available updates
  	  echo "Your system is up to date!"
	fi
	# If not root, cleanup tmp AVAILDIR
	if [ `id -u` != "0" ] ; then rm -rf "${AVAILDIR}" ; fi
	exit 0
}

exit_err() {
	echo "ERROR: ${1}"
	exit 1
}

# Make sure we aren't doing stand-alone apps at same time
sanity_check_updates() {
	hRelease=no
	hSalone=no
	tot=0
	for up in `echo $1 | sed 's|,| |g'`
	do
	  tot=`expr $tot + 1`
  	  echo $up | grep "release-" >/dev/null 2>/dev/null
	  if [ $? -eq 0 ] ; then 
	    mV=`cat ${AVAILDIR}/${SYSVER}/major-update | grep "^Version:" | sed 's|Version: ||g'`
	    if [ "$up" != "release-$mV" ] ; then
	      exit_err "Invalid major release for update!"
            fi
	    hRelease=yes 
            continue
          fi	

	  # If this is a pkg update
	  if [ "$up" = "pkg-updates" ] ; then continue ; fi

	  uF="${AVAILDIR}/${SYSVER}/${up}.upd"
  	  if [ ! -e "${uF}" ] ; then exit_err "Invalid update: ${up}" ; fi  

	  # See if this update must be standlone
	  pSA=`cat ${uF} | grep "^StandAlone:" | sed 's|StandAlone: ||g'`
	  if [ "$pSA" = "YES" ] ; then hSalone="yes" ; fi
	
	done

        # If doing too many standalones
	if [ "$hSalone" = "yes" -a $tot -gt 1 ] ; then
  	  exit_err "One or more updates must be installed stand-alone!"
	fi

	# If doing a new release must be standalone
	if [ "$hRelease" = "yes" -a $tot -gt 1 ] ; then
  	  exit_err "Updating to a new release must be done stand-alone!"
	fi
}

# Function which uses "fetch" to download a file, and display a progress report
fetch_file()
{
  local FETCHFILE="$1"
  local FETCHOUTFILE="$2"
  local EXITFAILED="$3"

  local numAtt=0

  while
  z=1
  do
    numAtt=`expr $numAtt + 1`
    # If the var PCFETCHGUI is unset, use regular fetch command
    if [ -z "$PCFETCHGUI" ] ; then
      fetch -o ${FETCHOUTFILE} "${FETCHFILE}"
      if [ $? -eq 0 ] ; then return 0 ; fi
      if [ $numAtt -gt 4 ] ; then return 1 ; fi
      # Sleep before retrying a failed download
      sleep 30 
      continue
    fi

    SIZEFILE="${DOWNLOADDIR}/.fetchSize"
    EXITFILE="${DOWNLOADDIR}/.fetchExit"

    rm ${SIZEFILE} 2>/dev/null >/dev/null
    rm ${FETCHOUTFILE} 2>/dev/null >/dev/null

    fetch -a -s "${FETCHFILE}" >${SIZEFILE}
    SIZE="`cat ${SIZEFILE}`"
    SIZE="`expr ${SIZE} / 1024 2>/dev/null`"
    echo "FETCH: ${FETCHFILE}"
    echo "FETCH: ${FETCHOUTFILE}" >>${TRIGGERFILE}
 
    ( fetch -o ${FETCHOUTFILE} "${FETCHFILE}" >/dev/null 2>/dev/null ; echo "$?" > ${EXITFILE} ) &
    PID="$!"
    while
    z=1
    do

      if [ -e "${FETCHOUTFILE}" ]
      then
        DSIZE=`du -k ${FETCHOUTFILE} | tr -d '\t' | cut -d '/' -f 1`
        if [ $(is_num "$DSIZE") ] ; then
        if [ $SIZE -lt $DSIZE ] ; then DSIZE="$SIZE"; fi 
      	  echo "SIZE: ${SIZE} DOWNLOADED: ${DSIZE}"
    	  echo "SIZE: ${SIZE} DOWNLOADED: ${DSIZE}" >>${TRIGGERFILE}
        fi
      fi

      # Check if the download is finished
      ps -p ${PID} >/dev/null 2>/dev/null
      if [ $? -ne 0 ]
      then
      break;
      fi

      sleep 1
    done

    echo "FETCHDONE"

    EXIT="`cat ${EXITFILE}`"
    rm ${SIZEFILE} 2>/dev/null >/dev/null
    rm ${EXITFILE} 2>/dev/null >/dev/null

    if [ "${EXIT}" != "0" -a "$EXITFAILED" = "1" ]; then
      if [ $numAtt -gt 4 ] ; then 
        exit_err "Error: Failed to download ${FETCHFILE}"
      else
	# Sleep before retrying a failed download
        sleep 30 
	continue
      fi
    fi


    if [ "${EXIT}" = "0" ]; then
      return 0
    else
      if [ $numAtt -gt 4 ] ; then 
        return -1
      else
	sleep 1
	continue
      fi
    fi
  done

};

start_pcbsd_patch() {
	up="$1"

   	if [ -e "${INSDIR}/${SYSVER}/${up}" ]; then 
	  exit_err "Patch $up already installed!"
	fi

        # Start downloading the patch
        UPDFILE="${AVAILDIR}/${SYSVER}/${up}" 

        # Set the URL based on file / mirror
        FILE="`cat ${UPDFILE} | grep '^FileURL:' | cut -d ' ' -f 2`"
        PATCHNAME="`cat ${UPDFILE} | grep '^Name:' | sed -e 's|: |:|g' | cut -d ':' -f 2`"
        FILENAME="`basename ${FILE}`"
        FILEMD5="`cat ${UPDFILE} | grep '^MD5:' | cut -d ' ' -f 2`"
        FILEURL="${MIRRORURL}${FILE}"
        FILEURL="`echo ${FILEURL} | sed -e 's|://|:::|g' | sed -e 's|//|/|g' | sed -e 's|:::|://|g'`"       

	# Start downloading the patch
        touch ${TRIGGERFILE}
        echo "DOWNLOADING: ${PATCHNAME}"
        echo "DOWNLOADING: ${PATCHNAME}" >${TRIGGERFILE}
	fetch_file "${FILEURL}" "${DOWNLOADDIR}/${FILENAME}" "1"
        if [ "$?" = "0" ]
        then
          if [ "$FILEMD5" != "`md5 -q ${DOWNLOADDIR}/${FILENAME} 2>/dev/null`" ]
          then
            # Download MD5 doesn't match! Delete the file
            rm ${DOWNLOADDIR}/${FILENAME}
            echo "FAILED: ${PATCHNAME}" >${TRIGGERFILE}
            exit_err "Failed to download: ${PATCHNAME}"
          else 
            echo "DOWNLOADFINISHED: ${PATCHNAME}"
            echo "DOWNLOADFINISHED: ${PATCHNAME}" >${TRIGGERFILE}
          fi
        else
          rm ${DOWNLOADDIR}/${FILENAME} >/dev/null 2>/dev/null
          echo "FAILED: ${PATCHNAME}" >${TRIGGERFILE}
          exit_err "Failed to download: ${PATCHNAME}"
        fi

        echo "INSTALLING: ${PATCHNAME}" >${TRIGGERFILE}
        sleep 4

        PATCHTMPDIR="`mktemp -d ${DOWNLOADDIR}/patchInstallXXXXX`"
        tar xvJf ${DOWNLOADDIR}/${FILENAME} -C ${PATCHTMPDIR} 2>/dev/null
        cd ${PATCHTMPDIR}
        sh update.sh
        if [ $? -eq 0 ]
        then
          cp $UPDFILE ${INSDIR}/${SYSVER}/
          echo "INSTALLFINISHED: ${PATCHNAME}"
          echo "INSTALLFINISHED: ${PATCHNAME}" >${TRIGGERFILE}
	else
          echo "INSTALLFAILED: ${PATCHNAME}" >${TRIGGERFILE}
	  exit_err "INSTALLFAILED: ${PATCHNAME}"
        fi

        cd ${AVAILDIR}/${SYSVER}
        rm -rf ${PATCHTMPDIR} 
        rm ${DOWNLOADDIR}/${FILENAME} >/dev/null 2>/dev/null
}

# Make sure we have a numeric
is_num()
{
  expr $1 + 1 2>/dev/null
  return $?
}

start_major_update() {
 	up="`echo $1 | sed 's|release-||g'`"

	# Create the stage directory for this update
 	STAGEDIR="${DOWNLOADDIR}/${up}" 
	if [ ! -e "${STAGEDIR}" ] ; then
	  mkdir -p ${STAGEDIR}
	fi
	
	# Save the upgrade version
	echo "$up" > ${STAGEDIR}/sys-ver

	# Do the download portion now
	download_major_update

	# Start staging the files for updating
	stage_files_major_update

	# Notify User
  	if [ -z "$PCFETCHGUI" ] ; then
          echo "The system update downloaded successfully!"
          echo ""
          echo "Please reboot your system to begin the upgrade process."
	
	else
          echo "READYREBOOT"
	fi

}

stage_files_major_update() {
	# First confirm we have some critical files
	if [ ! -e "${STAGEDIR}/xtra-data/upgrade-excludes" ] ; then
	  exit_err "Missing upgrade-excludes!"
	fi
	if [ ! -e "${STAGEDIR}/xtra-data/upgrade-merges" ] ; then
	  exit_err "Missing upgrade-merges!"
	fi

  	if [ ! -z "$PCFETCHGUI" ] ; then
          echo "DONEDOWNLOAD"
        fi

	# Remove comments from the files
	cat ${STAGEDIR}/xtra-data/upgrade-excludes | grep -v "^#" > ${STAGEDIR}/xtra-data/upgrade-excludes.new
	mv ${STAGEDIR}/xtra-data/upgrade-excludes.new ${STAGEDIR}/xtra-data/upgrade-excludes
	cat ${STAGEDIR}/xtra-data/upgrade-merges | grep -v "^#" > ${STAGEDIR}/xtra-data/upgrade-merges.new
	mv ${STAGEDIR}/xtra-data/upgrade-merges.new ${STAGEDIR}/xtra-data/upgrade-merges

	# Check if we have a master system file listing and save it
	if [ -e "/usr/local/share/pcbsd/base-ports/system-file.list" ] 
	then
	  cp /usr/local/share/pcbsd/base-ports/system-file.list ${STAGEDIR}/xtra-data/system-file.list.old
	fi

        # Rename the stagedir
	if [ -e "$MUSTAGEDIR" ] ; then rm -rf "$MUSTAGEDIR" ; fi
	mv ${STAGEDIR} ${MUSTAGEDIR}
	STAGEDIR="$MUSTAGEDIR"
	
	# Copy over the rc scripts
	cp /etc/rc /etc/rc.backup
	cp ${PROGDIR}/scripts/mu-rc /etc/rc

	# Copy over the update scripts
	cp ${PROGDIR}/scripts/mu-stage1 ${STAGEDIR}/doupdate.sh
	cp ${PROGDIR}/scripts/mu-rc ${STAGEDIR}/
	cp ${PROGDIR}/scripts/mu-stage1 ${STAGEDIR}/
	cp ${PROGDIR}/scripts/mu-stage2 ${STAGEDIR}/
}

download_major_update() {

	# Set the mirror locaion for this major update
	MIRRORDIR="${MIRRORURL}/${up}/`uname -m`/netinstall"
        MIRRORDIR="`echo ${MIRRORDIR} | sed -e 's|://|:::|g' | sed -e 's|//|/|g' | sed -e 's|:::|://|g'`"       
	echo "STARTINGUPDATE: $up"
	
	# Download the files in dList
  	if [ -z "$PCFETCHGUI" ] ; then
          echo "Downloading Master Files..."
	else
          echo "MASTERFILECOUNT: 5"
	fi
	dList="PCBSD.tbz PCBSD.tbz.count PCBSD.tbz.md5 xtra-data.tbz xtra-data.tbz.md5"
	for dFile in $dList
	do

	  # See if we have the file already
	  if [ -e "${STAGEDIR}/${dFile}" -a -e "${STAGEDIR}/${dFile}.md5" ] ; then
	    # File checksum is good, we can skip
	    if [ "`md5 -q ${STAGEDIR}/$dFile`" = "`cat ${STAGEDIR}/${dFile}.md5`" ] ; then
	      continue
	    fi
	  fi

	  # Download the file
	  fetch_file "${MIRRORDIR}/$dFile" "${STAGEDIR}/$dFile" "1" "0"
	  if [ $? -ne 0 ] ; then
            rm ${STAGEDIR}/$dFile >/dev/null 2>/dev/null
            echo "FAILED: ${up}" >${TRIGGERFILE}
            exit_err "Failed to download: ${STAGEDIR}/$dFile"
	  fi
	done

	# Verify the md5 sums of .tbz files
	mList="PCBSD.tbz xtra-data.tbz"
	for dFile in $mList
	do
	  echo "$dFile" | grep "\.tbz" >/dev/null 2>/dev/null
	  if [ $? -ne 0 ] ; then continue ; fi
	  if [ "`md5 -q ${STAGEDIR}/$dFile`" != "`cat ${STAGEDIR}/${dFile}.md5`" ] ; then
	    exit_err "File $dFile failed the checksum"
	  fi
	done

	# Extract xtra-data
	cd ${STAGEDIR}
	mkdir xtra-data >/dev/null 2>/dev/null
	cd xtra-data
	tar xvjf "${STAGEDIR}/xtra-data.tbz" >/dev/null 2>/dev/null
	if [ $? -ne 0 ] ; then
	  exit_err "Failed reading xtra-data for update"
	fi

	# Get list of pkgs we need to fetch
	generate_pkg_fetch_list "$STAGEDIR"

  	if [ -z "$PCFETCHGUI" ] ; then
          echo "Downloading Packages..."
	else
          echo "PKGFILECOUNT: $DLPKGCOUNT"
	fi
	mkdir "${STAGEDIR}/packages" >/dev/null 2>/dev/null
	for dFile in $DLPKGLIST
	do
	  # See if we have the file already
	  if [ -e "${STAGEDIR}/packages/${dFile}.tbz" -a -e "${STAGEDIR}/packages/${dFile}.tbz.md5" ] ; then
	    # File checksum is good, we can skip
	    if [ "`md5 -q ${STAGEDIR}/packages/${dFile}.tbz`" = "`cat ${STAGEDIR}/packages/${dFile}.tbz.md5`" ] ; then
  	      if [ ! -z "$PCFETCHGUI" ] ; then
	        echo "FETCH: ${STAGEDIR}/packages/$dFile OK"
	        echo "FETCH: ${STAGEDIR}/packages/${dFile}.md5 OK"
              fi
	      continue
	    fi
	  fi

	  # Download the file
	  fetch_file "${MIRRORDIR}/packages/${dFile}.tbz" "${STAGEDIR}/packages/${dFile}.tbz" "1" "0"
	  if [ $? -ne 0 ] ; then
            echo "FAILED: ${dFile}.tbz" >${TRIGGERFILE}
            exit_err "Failed to download: ${STAGEDIR}/packages/${dFile}.tbz"
	  fi

	  # Download the md5 file
	  fetch_file "${MIRRORDIR}/packages/${dFile}.tbz.md5" "${STAGEDIR}/packages/${dFile}.tbz.md5" "1" "0"
	  if [ $? -ne 0 ] ; then
            echo "FAILED: ${dFile}.tbz.md5" >${TRIGGERFILE}
            exit_err "Failed to download: ${STAGEDIR}/packages/${dFile}.tbz.md5"
	  fi

	  # Confirm the md5
	  if [ "`md5 -q ${STAGEDIR}/packages/${dFile}.tbz`" !=  "`cat ${STAGEDIR}/packages/${dFile}.tbz.md5`" ] ; then
            echo "FAILED: ${dFile}.tbz" >${TRIGGERFILE}
            exit_err "Checksum failed for: ${STAGEDIR}/packages/${dFile}.tbz"
	  fi
	done

}

start_pkg_updates() {
	# Start doing pkg-updates
	cd "${AVAILDIR}/${SYSVER}"

        # Do we have update data
	if [ ! -e "base-ports.tlz" ] ; then
   	  exit_err "No package updates available!"
        fi

        # Verify the signature of the base-ports.tlz
	openssl dgst -sha1 -verify ${SKEY} \
		-signature base-ports.tlz.sha1 \
              	base-ports.tlz >/dev/null 2>/dev/null
        if [ $? -ne 0 ]; then
   	  exit_err "No package updates available!"
	fi

    	rm -rf base-ports
	tar xvJf base-ports.tlz >/dev/null 2>/dev/null

	# If we have a index, check installed pkgs for updates
	if [ ! -e "base-ports/master-pkg-index" ] ; then
   	  exit_err "No package updates available!"
        fi

	fPkgUp=0

	# Checkout the installed pkgs and compare to master list
	ls /var/db/pkg > /tmp/.pkgList.$$
	cat base-ports/master-pkg-index | cut -d ":" -f 1-2 | sed 's|:|-|g' > /tmp/.pkgList2.$$
	diff /tmp/.pkgList.$$ /tmp/.pkgList2.$$ | grep '^<' | sed 's|< ||g' > /tmp/.dList.$$
	rm /tmp/.pkgList.$$
	rm /tmp/.pkgList2.$$
	while read pLine
	do
	  pName=`echo $pLine | rev | cut -d "-" -f 2-25 | rev`
	  pVer=`echo $pLine | rev | cut -d "-" -f 1 | rev`
		
	  # Make sure this version isn't in our index
	  grep "^${pName}:${pVer}" base-ports/master-pkg-index >/dev/null 2>/dev/null
	  if [ $? -eq 0 ] ; then continue ; fi

	  # Get the info from master-pkg-index
	  iLine=`grep "^${pName}:" base-ports/master-pkg-index`
	  if [ -z "$iLine" ] ; then continue ; fi

	  iFile="`echo $iLine | cut -d ':' -f 4`"

	  # Is this version different?
	  if [ "$pVer" = "$iVer" ] ; then continue ; fi

	  if [ $fPkgUp -eq 0 ] ; then fPkgUp=1 ; fi

	  # Save what pkg will be updated
	  echo "${pLine} ${iFile}" >> /tmp/.uList.$$

	done < /tmp/.dList.$$
	rm /tmp/.dList.$$

	# Exit if no updates found
	if [ $fPkgUp -ne 1 ] ; then exit_err "No package updates available"; fi
    	# Create the stage directory for this update
        STAGEDIR="${DOWNLOADDIR}/.pkg-updates.$$"
        if [ ! -e "${STAGEDIR}" ] ; then
          mkdir -p ${STAGEDIR}
        fi

	# Set the mirror locaion for this major update
	MIRRORDIR="${MIRRORURL}/${SYSVER}/`uname -m`/netinstall"
        MIRRORDIR="`echo ${MIRRORDIR} | sed -e 's|://|:::|g' | sed -e 's|//|/|g' | sed -e 's|:::|://|g'`"       

  	if [ ! -z "$PCFETCHGUI" ] ; then
	  echo "PKGDLCOUNT: `wc -l /tmp/.uList.$$ | awk '{print $1}'`"	
	fi

	# Start downloading the files
	while read pLine
	do
	  oPkg="`echo $pLine | cut -d ' ' -f 1`"
	  nPkg="`echo $pLine | cut -d ' ' -f 2`"

	  # Get the new package
	  fetch_file "${MIRRORDIR}/packages/$nPkg" "${STAGEDIR}/$nPkg" "1" "0"
	  if [ $? -ne 0 ] ; then
            rm -rf ${STAGEDIR} >/dev/null 2>/dev/null
	    rm /tmp/.uList.$$
            exit_err "Failed to download: ${MIRRORDIR}/packages/$nPkg"
          fi

	  # Grab the MD5 file
	  fetch_file "${MIRRORDIR}/packages/${nPkg}.md5" "${STAGEDIR}/${nPkg}.md5" "1" "0"
	  if [ $? -ne 0 ] ; then
            rm -rf ${STAGEDIR} >/dev/null 2>/dev/null
	    rm /tmp/.uList.$$
            exit_err "Failed to download: ${MIRRORDIR}/packages/$nPkg"
          fi
	
	  if [ `md5 -q ${STAGEDIR}/${nPkg}` != `cat ${STAGEDIR}/${nPkg}.md5` ]
	  then
            rm -rf ${STAGEDIR} >/dev/null 2>/dev/null
	    rm /tmp/.uList.$$
            exit_err "Invalid checksum for ${nPkg}. Please try again later."
	  fi
	done < /tmp/.uList.$$

	# Now start updating the package list 
  	if [ ! -z "$PCFETCHGUI" ] ; then
	  echo "PKGUPCOUNT: `wc -l /tmp/.uList.$$ | awk '{print $1}'`"	
	fi
	while read pLine
	do
	  oPkg="`echo $pLine | cut -d ' ' -f 1`"
	  nPkg="`echo $pLine | cut -d ' ' -f 2`"
	  nPkgNoExt="`echo $nPkg | sed 's|.tbz||g'`"
  	  if [ ! -z "$PCFETCHGUI" ] ; then
	    echo "PKGUPDATE: $oPkg -> $nPkgNoExt"
	  else
	    echo "Updating $oPkg -> $nPkgNoExt"
	  fi
	
	  pkg_delete -f ${oPkg} >/dev/null 2>/dev/null
	  if [ $? -ne 0 ] ; then
	    echo "WARNING: Failed to uninstall ${oPkg}"
	  fi

	  pkg_add -f "${STAGEDIR}/${nPkg}" >/dev/null 2>/dev/null
	  if [ $? -ne 0 ] ; then
	    echo "WARNING: Failed to install ${STAGEDIR}/${nPkg}"
	  fi
	done < /tmp/.uList.$$

	# Clean up, all done
  	if [ ! -z "$PCFETCHGUI" ] ; then echo "PKGUPDATEFINISHED" ; fi
	rm -rf ${STAGEDIR}
	rm /tmp/.uList.$$
}

generate_pkg_fetch_list() {
	local STAGEDIR="$1"
  	
 	# First get a list of meta-pkgs that are installed
	local mIns="base-system"
	pc-metapkgmanager list | grep "^Meta Package:" | sed 's|Meta Package: ||g' | grep -v "base-system" >${STAGEDIR}/.mPkgs.$$
	while read mL
	do
	  pc-metapkgmanager status "$mL" | grep "is installed" >/dev/null 2>/dev/null	
	  if [ $? -eq 0 ] ; then
	    mIns="$mIns $mL"
	  fi

	done < ${STAGEDIR}/.mPkgs.$$
	rm ${STAGEDIR}/.mPkgs.$$

	# Now get a list of pkgs these meta-pkgs require
        DLPKGLIST=""
	for mP in $mIns
	do
	  if [ ! -e "${STAGEDIR}/xtra-data/base-ports/$mP/full-pkg-list" ] ; then
	    continue;
	  fi
	  cat "${STAGEDIR}/xtra-data/base-ports/$mP/full-pkg-list" >> ${STAGEDIR}/.pList.$$
	done
	
	sort ${STAGEDIR}/.pList.$$ | uniq > ${STAGEDIR}/.pList2.$$
	mv ${STAGEDIR}/.pList2.$$ ${STAGEDIR}/.pList.$$

        DLPKGCOUNT=0
	while read pL
	do
          DLPKGLIST="$DLPKGLIST ${pL}"
          DLPKGCOUNT="`expr $DLPKGCOUNT + 1`"
	done < ${STAGEDIR}/.pList.$$
	rm ${STAGEDIR}/.pList.$$
	  
}

do_install() {
        # Make sure we are root and have specified updates to install
	if [ `id -u` != "0" ] ; then exit_err "Must be run as root!" ; fi
	if [ -z "$1" ] ; then exit_err "No updates specified to install!"; fi

	sanity_check_updates ${1}

	# CD to the patch directory for this version
	cd ${AVAILDIR}/${SYSVER}

	# Begin to update the selected items
	for up in `echo $1 | sed 's|,| |g'`
	do

	  # If this is a major update, start it up!
  	  echo $up | grep "release-" >/dev/null 2>/dev/null
	  if [ $? -eq 0 ] ; then 
	    start_major_update "$up"
	    exit 0
	  fi

	  # Check if this is a pkg-update request or regular patch
          if [ "$up" == "pkg-updates" ] ; then
            start_pkg_updates
          else
	    # Doing regular pcbsd patch
	    start_pcbsd_patch "${up}.upd"
          fi
	done 

        # All Finished!
        exit 0
}

is_net_up() {
	ping -c 1 www.pcbsd.org >/dev/null 2>/dev/null
	return $?
}

# Set the program location

# Check if we have proxy settings
if [ -e "${PCBSD_ETCCONF}" ] ; then
	PC_PROXYURL="`cat ${PCBSD_ETCCONF} | grep 'PCBSD_PROXYURL: ' | sed 's|PCBSD_PROXYURL: ||g'`"
	PC_PROXYPORT="`cat ${PCBSD_ETCCONF} | grep 'PCBSD_PROXYPORT: ' | sed 's|PCBSD_PROXYPORT: ||g'`"
	PC_PROXYTYPE="`cat ${PCBSD_ETCCONF} | grep 'PCBSD_PROXYTYPE: ' | sed 's|PCBSD_PROXYTYPE: ||g'`"
	PC_PROXYUSER="`cat ${PCBSD_ETCCONF} | grep 'PCBSD_PROXYUSER: ' | sed 's|PCBSD_PROXYUSER: ||g'`"
	PC_PROXYPASS="`cat ${PCBSD_ETCCONF} | grep 'PCBSD_PROXYPASS: ' | sed 's|PCBSD_PROXYPASS: ||g'`"
fi

# Create the PROXY variables based upon proxy information supplied
if [ ! -z "$PC_PROXYURL" ] ; then
	if [ ! -z "$PC_PROXYPORT" ] ; then
		HTTP_PROXY="${PC_PROXYURL}:${PC_PROXYPORT}"
		export HTTP_PROXY
	else
		HTTP_PROXY="${PC_PROXYURL}"
		export HTTP_PROXY
	fi
	if [ ! -z "$PC_PROXYUSER" ] ; then
		if [ ! -z "$PC_PROXYPASS" ] ; then
			HTTP_PROXY_AUTH="basic:*:${PC_PROXYUSER}:${PC_PROXYPASS}"
			export HTTP_PROXY_AUTH
		fi
	fi
fi

# Check if we have an update folder for the version we are on
if [ ! -d "${AVAILDIR}/${SYSVER}" ] ; then mkdir -p ${AVAILDIR}/${SYSVER} ; fi

if [ "`id -u`" = "0" ] ; then
  # Make the installed directory for this version
  if [ ! -d "${INSDIR}/${SYSVER}" ] ; then mkdir -p ${INSDIR}/${SYSVER} ; fi

  # Make the ignore directory for this version
  if [ ! -d "${IGNDIR}/${SYSVER}" ] ; then mkdir -p ${IGNDIR}/${SYSVER} ; fi
fi

case $1 in
	check) do_check ;;
	install) # First update our available list with latest from server 
		 ${0} check >/dev/null 2>/dev/null ;
                 do_install "${2}" ;;
	*) show_usage ;;
esac

exit 0
