#!/bin/bash
# $Header: /cvs/WebShield/wsrc/files/mgmt/av-update,v 1.26.2.1 2005/02/16 11:18:18 bwhittak Exp $
#
# Copyright (C) 2004 Networks Associates Technology Inc. All rights reserved.
#
. /var/NAIENV/.profile.vars
PATH=$wsPATH:$PATH
. message_functions.bash	# message localisation

shopt -s extglob	# fancy globbing
exec </dev/null		# don't need any inputs
md5s()
{
	/usr/bin/md5sum $1 | cut -f1 -d" "
}
# default values
declare -i max_rtry=99999			# max retries - huge
DEF_eng_dir="$AVENGINEDIR"			# destination path on local host
eng_dir="$DEF_eng_dir"
DEF_dat_dir="$AVDATDIR"				# destination path on local host
dat_dir="$DEF_dat_dir"
DEF_FTPSERVER="ftp.nai.com"			# ftp server to download from
server="$DEF_FTPSERVER"
DEF_UPDATEDIR="/virusdefs/4.x/"			# source path on ftpserver host
srcpath="$DEF_UPDATEDIR"
DEF_USERNAME="anonymous"
user="$DEF_USERNAME"
DEF_PASSWORD="webshield_user@mcafee.com"
pass="$DEF_PASSWORD"
get_eng=false
get_dat=false
unset proxy pport puser ppass
eng_zip='' dat_zip=''

# what do I call myself?
declare -r me=${0##*/}
declare -r cmdline="$me $*"

# Process options
while [[ $# -gt 0 ]]; do
    case $1 in
    ('-retries') max_rtry=${2%%[^0-9]*}; shift;;
    ('-engpath') eng_dir="$2"; shift;;
    ('-datpath') dat_dir="$2"; shift;;
    ('-engzip') eng_zip="$2" get_eng=true; shift;;
    ('-datzip') dat_zip="$2" get_dat=true; shift;;
    ('-eng') get_eng=true ;;
    ('-dat') get_dat=true ;;
    ('-local') server="";;
    ('-src') server="$2"; shift;;
    ('-srcpath') srcpath="$2"; shift;;
    ('-user') user="$2"; shift;;
    ('-pass') pass="$2"; shift;;
    ('-proxy') proxy="$2"; shift;;
    ('-pport') pport="$2"; shift;;
    ('-puser') puser="$2"; shift;;
    ('-ppass') ppass="$2"; shift;;
    (*) echo "$me bad option: $1" >&2;;
    esac
    shift
done

# if -engzip or -datzip specified then assume local
[[ -n "$eng_zip" || -n "$dat_zip" ]] && server="" user="" pass="" proxy=""
[[ -n "$proxy" ]] || puser="" ppass="" pport=""
# if neither -eng nor -dat specified then assume both
$get_eng || $get_dat || get_eng=true get_dat=true
# eng_zip and dat_zip unset if not required, set empty if not obtained
$get_eng || unset eng_zip
$get_dat || unset dat_zip
eng_dir=${eng_dir%%*(/)}	# remove trailing / if present
dat_dir=${dat_dir%%*(/)}	# remove trailing / if present
# URL quoted password
qpass=$(echo -nE "$pass" | perl -p -e 's/\W/sprintf "%%%.2x", ord($&)/ge')

# constants
declare -ir EXTRA_KDAYS=30	# keep extra.dat files for 30 days
				# also used for purging backup dat files
				# exported for av-install-dat
declare -ir TRYWAIT=60		# initial wait between tries (seconds)
declare -ir MAXTIME=6*60*60	# how long will we keep trying
declare -r inst="$me.$(date -u '+%Y%m%d%H%M%S').$$"
declare -r tmp=/tmp/$inst	# temporary directory
declare -r log=/var/log/$inst.log	# log file
exec >"$log" 2>&1	# start log file
declare -r eng_stat=$XMLCONFDIR/eng_update_status
declare -r dat_stat=$XMLCONFDIR/dat_update_status

# patterns for decoding *.ini
declare -r patFS='FileSize='
declare -r patFP='FilePath='
declare -r patFN='FileName='
declare -r patEV='EngineVersion='
declare -r patDV='DATVersion='
declare -r patMD='MD5='
declare -r cCR=$'\r' cNL=$'\n'

# event codes
declare -r PROGevent=UPDATE_PROGRESS
declare -r CHNGevent=AV_UPDATE_CHANGE
declare -r NOCHevent=AV_UPDATE_NOCHANGE
declare -r FAILevent=AV_UPDATE_FAIL
declare -r INTRevent=AV_UPDATE_INTR

# functions


Event()		# report an event
{
    evrep -n $me -i AUDIT_ID -v $inst "$@" \
	${WS_SESSION:+-i UI_SESSION_ID -v "$WS_SESSION"} \
	${WS_USER_ID:+-i USER_NAME -v "$WS_USER_ID"} \
	${WS_SOURCE_IP:+-i SOURCE_IP -v "$WS_SOURCE_IP"} \
	${server:+-i UPDATE_SERVER -v "$server"} \
	${user:+-i UPDATE_USER -v "$user"} \
	${pass:+-i UPDATE_PASS -v "*******"} \
	${proxy:+-i UPDATE_PROXY -v "$proxy"} \
	${puser:+-i UPDATE_PROXY_USER -v "$puser"} \
	${ppass:+-i UPDATE_PROXY_PASS -v "*******"} \
	${pport:+-i UPDATE_PROXY_PORT -v "$pport"} \
	${engver:+-i AV_ENG_VER -v "$engver"} \
	${datver:+-i AV_DAT_VER -v "$datver"} \
	${engzip+${engEV:+-i NEW_AV_ENG_VER -v "$engEV"}} \
	${datzip+${datDV:+-i NEW_AV_DAT_VER -v "$datDV"}} \
	${done_tries:+-i NUM_TRIES -v "$done_tries"}
}

declare -a bad_reason	# reason array for last bad event
GoodEvent()	# a good update progress event
{
    local saverr=$?	# save previous error
    bad_reason=()
    Event -e $PROGevent::"$@"
    return $saverr	# return saved error
}
BadEvent()	# a bad update progress event
{
    local saverr=$?	# save previous error
    bad_reason=( "$@" )	# save the reason for possible exit
    Event -e $PROGevent::"$@"
    return $saverr	# return saved error
}

StampOut()	# print args with timestamp
{
    printf "$(date '+%Y-%m-%d%a%T%z'): %s\n" "$@"
}

SendLog()	# send stuff to syslog and echo to stdout
{
    local saverr=$?	# save previous error
    [[ $# -gt 0 ]] || return 0	# nothing to send
    printf '%s\n' "$@" | logger -t "$me[$$]"
    StampOut "$@"
    return $saverr	# return saved error
}

declare -a exit_event	#event array set by Exit caller for exit event
Exit()		# the standard way out
{
    error=${1:-$?}		# set exit code
    shift
    SendLog "$me: Exit $error: $*"
    ReportProgress _TR_ "update_exit" $"update finished: exit code %s" "$error"
    # send events
    [[ -n $exit_event ]] || exit_event=$FAILevent
    Event -e "${exit_event[@]}"
    # clean up and go home
    [[ $tmp == /tmp/* ]] && rm -rf $tmp
    exit $error
}

showstate()	# note state
{
    local flag=ed
    [[ $1 == -* ]] && { flag=${1#-}; shift; }
    [[ $flag == *e* && -n "${eng_zip+is_set}" ]] &&
	echo "$*" ${engEV:+"_NEW_VER_ $engEV _VER_NEW_"} >$eng_stat
    [[ $flag == *d* && -n "${dat_zip+is_set}" ]] &&
	echo "$*" ${datDV:+"_NEW_VER_ $datDV _VER_NEW_"} >$dat_stat
    return 0
}

BadExit()	# failed for some reason
{
    if [[ $1 == "-e" ]]; then
	exit_event=( $2 )
	shift 2
    else
	exit_event=( $FAILevent${bad_reason:+"::${bad_reason[@]}"} )
    fi
    #evrep engine update failed
    showstate "_FAILED_"
    Exit 1 "$@"
}

trap 'BadExit -e $INTRevent on signal' hup int term

GoodExit()	# all happy
{
    if [[ $1 == "-e" ]]; then
	exit_event=( $2 )
	shift 2
    fi
    #evrep engine update worked
    showstate "_DONE_"
    Exit 0 "$@"
}

ReadINI()	# extract values from update.ini file
{
    # $1 - section header line
    # $2 - variable name prefix
    local IFS=$cCR$cNL	# field separators <CR><LF> (any combination)
    local FS FP FN EV DV MD line
    for line in $(cat update.ini); do
	if [[ "$line" == '['* ]]; then
	    sect="$line"
	elif [[ "$sect" == "[$1]" ]]; then
	    case "$line" in
		($patFS*) FS="${line#$patFS}";;
		($patFP*) FP="${line#$patFP}";;
		($patFN*) FN="${line#$patFN}";;
		($patEV*) EV="${line#$patEV}";;
		($patDV*) DV="${line#$patDV}";;
		($patMD*) MD="${line#$patMD}";;
	    esac
	fi
    done
    printf '%s\n' \
	"${2}FS='$FS'" \
	"${2}FP='$FP'" \
	"${2}FN='$FN'" \
	"${2}EV='${EV//[^0-9]}'" \
	"${2}DV='${DV//[^0-9]}'" \
	"${2}MD='$MD'"
}

TimeOut()	# run a command but kill if it takes too long
{
    local time=$1	# first arg is the max time to run
    shift		# rest are the command
    "$@" <&0 &	# start command in background
    local p=$!	# pid of command
    (	# assasin will sleep a time then kill command if still running
	sleep $time  &&
	echo "$1 taking too long - killing it" &&
	kill $p &&
	sleep 1 &&
	kill -9 $p
    ) 2>/dev/null &
    wait $p		# wait for command to finish or be killed
    local err=$?	# collect its exit code
    kill $! 2>/dev/null	# kill the sleeping assasin
    return $err
}

GetFile()	# fetch a file by ftp
{
    mode=binary
    local size md5
    while [[ "$1" == '-'* ]]; do
	case $1 in
	    -a) mode=ascii;;
	    -b) mode=binary;;
	    -s) size=${2//[^0-9]}; shift;;
	    -m) md5=$2; shift;;
	    *) :;;
	esac
	shift
    done
    file=$1; shift
    local gtmp=$file.d.$$
    [[ -f "$file" ]] && mv "$file" "$file.last"
    # set kill time for transfers max of 10 min or time for size at 10byte/sec
    local ktime=$(( size > 6000 ? size/10 : 600 ))
    for target; do
	GoodEvent UpdateFile -i FILE_NAME -v "$file" \
	    -i URL -v "ftp://$user@$server/${target##*(/)}"
	ReportProgress _TR_ "UpdateFile" $"fetch %s from %s" \
	    "$file" "ftp://$user@$server/${target##*(/)}"
	SendLog "fetch $file ${proxy:+via $proxy }from ftp://$user@$server/${target##*(/)}"
	if [[ -n "$proxy" ]]; then
	    # try the proxy with http
	    # apply timeout as wget has been known to hang
	    StampOut "try wget (timeout $ktime)"
	    ftp_proxy="$proxy${pport:+:$pport}" \
		TimeOut $ktime \
		wget -d -v -O "$file" -g off \
                    ${puser:+"--proxy-user=$puser"} \
		    ${ppass:+"--proxy-passwd=$ppass"} \
		    "ftp://$user${qpass:+:$qpass}@$server/${target##*(/)}"
	    CheckFile "$file" "$size" "$md5" && return 0
	    # try the proxy with ftp
	    StampOut "try ftp (timeout $ktime)"
	    printf '%s\n' \
		    "user $user@$server${pass:+ $pass}" \
		    "$mode" \
		    "get $target $file" \
		| TimeOut $ktime ftp -v -n "$proxy" ${pport:+ "$pport"}
	    CheckFile "$file" "$size" "$md5" && return 0
	else
	    StampOut "try ftp"
	    printf '%s\n' \
		    "user $user${pass:+ $pass}" \
		    "$mode" \
		    "get $target $file" \
		| ftp -v -n "$server"
	    CheckFile "$file" "$size" "$md5" && return 0
	fi
	# try with ncftpget
	StampOut "try ncftpget"
	local o
	for o in -E -F; do	# first active, then passive
	    ncftpget $o -t $ktime -r 1 -d stderr -c >$file \
		-u "$user${proxy:+@$server}" \
		${pass:+-p "$pass"} \
		${pport:+-P "$pport"} \
		"${proxy:-$server}" \
		$target
	    CheckFile "$file" "$size" "$md5" && return 0
	done
    done
    SendLog "$file: fetch failed (details in $log)"
    return 1
}

CheckFile()	# check a file's size and md5
{
    local quiet
    if [[ $1 == "-s" ]]; then
	quiet=:
	shift
    fi
    local file=$1 size=$2 md5=$3
    if [[ ! -s "$file" ]]; then
	$quiet BadEvent UpdateFileFail -i FILE_NAME -v "$file"
	echo "$file: no data" >&2
	return 1
    fi
    local sz=${size:+$(wc -c <$file)}
    if [[ ! "$size" -eq "$sz" ]]; then
	$quiet BadEvent UpdateFileMismatch -i FILE_NAME -v "$file"
	echo "$file: mismatched size $sz (expected $size)" >&2
	return 1
    fi
    local md=${md5:+$(md5s $file)}
    if [[ ! "$md5" == "$md" ]]; then
	$quiet BadEvent UpdateFileMismatch -i FILE_NAME -v "$file"
	echo "$file: mismatched md5 $md (expected $md5)" >&2
	return 1
    fi
    SendLog "$file: OK${size:+, size $size}${md5:+, md5 $md5}"
    GoodEvent UpdateFileOK -i FILE_NAME -v "$file"
    return 0
}

GetZIP()
{
    # $1 local filename
    # $2 version installed
    # $3 version available
    # $4 FileName
    # $5 FilePath
    # $6 FileSize
    # $7 MD5
    # $srcpath base path
	SendLog "require $1, ver $3 (have $2), size $6, md5 $7: $5 $4"
	local file=$1
	local vhave=$2 vwant=$3
	local fn=$4 fp=$5 size=$6 md5=$7
	local -a rn
	# check version on offer is better than we have installed
	[[ "$vwant" -gt "$vhave" ]] || return 1
	# check the file we have already fetched
	CheckFile -s "$file" "$size" "$md5" && return 0
	# check there's a file to fetch
	[[ -n "$fn" ]] || return 1
	# adjust the directory path and fetch the file
	[[ "$fp" == /* ]] || fp=$srcpath/${fp%/}/
	if [[ "$fp" == */ ]]; then
	    rn="$fp$fn"
	else
	    rn[1]=$fp
	    if [[ "$fp" != */"$fn" ]]; then
		rn[0]="$fp/$fn"
	    fi
	fi
	rn[2]=$srcpath/$fn	# last try - same place we got update.ini
	GetFile -b -s "$size" -m "$md5" "$file" "${rn[@]}"
}

UnZipList()	# unpack a zip package and output list of files extracted
{
    [[ -s "$zip" ]] || return 1
    [[ -n "$dir" ]] && mkdir -p "$dir" && cd "$dir"
    unzip -jLC "$zip" pkgdesc.ini >/dev/null
    IFS=$cCR$cNL		# field separators CR LF for loading pd
    if [[ -s pkgdesc.ini ]]; then
	pd=(`cat pkgdesc.ini`)	# load array of all lines in file
    fi
    rm -f pkgdesc.ini		# no need for the file now
    IFS=" ,	"		# field separators now space, tab, comma
    # find filenames list in array
    for l in "${pd[@]}"; do	# trot through pkgdesc.ini content array
	if [[ "$l" == '' || "$l" == '['* ]]; then	# section boundary
	    sec=$l
	elif [[ "$sec" == "[$type Files]" ]]; then	# interesting section
	    if [[ "$l" == 'Numberoffiles='+([0-9]) ]]; then
		num=${l#'Numberoffiles='}
	    elif [[ "$l" == @(Namesoffiles|Filenames)=* ]]; then
		files=( ${l#@(Namesoffiles|Filenames)=} )
	    fi
	fi
    done
    nf=${#files[@]}
    [[ $nf -gt 0 ]] || return 1
    unzip -jLC "$zip" "${files[@]}" >/dev/null || return 1
    # set mode bits sensibly
    chmod a=r "${files[@]}"
    # check the number of files
    [[ -n "$num" && "$num" -ne ${#files[@]} ]] && return 1
    # check the files
    for f in "${files[@]}"; do
	# bad thing if one of our specified files is missing
	[[ -f "$f" ]] || return 1
    done
    # check the MD5s
    for l in "${pd[@]}"; do	# trot through pkgdesc.ini content array
	if [[ "$l" == '' || "$l" == '['* ]]; then	# section boundary
	    sec=$l
	elif [[ "$sec" == '[MD5 CODE]' ]]; then	# interesting section
	    m=($l)	# split up line
	    # bad thing if one of our files doesn't match its MD5
	    [[ -f "${m[0]}" && "${m[1]}" != "$(md5s "${m[0]}")" ]] &&
		return 1
	fi
    done
    # can't find anything wrong here
    printf '%s\n' "${files[@]}"
}

UnZip()		# unpack a zip package and return list of files extracted
{
    local zip=$1; shift		# $1 zip file
    local type=$1; shift	# $2 type - DAT or Engine
    local dir=$1; shift		# $3 directory to work in
    local var=$1; shift		# $4 name of var for filename list
    local -a pd files m
    local num sec l f
    local IFS=$cNL		# field separators LF to split result
    [[ "$zip" != /* ]] && zip=$PWD/$zip
    local report='FAILED'
    ReportProgress _TR_ "update-unpacking" $"unpacking %s" "$zip"
    local res
    res=$(set -f; UnZipList) &&
	[[ -n "$var" ]] && eval ${var}='( $res )' && report='OK' ||
	BadEvent UpdateFileBad -i FILE_NAME -v "$zip"
    SendLog "$report unpacking $type $zip"
    return
}

# get current engine and DAT versions
export datver engver	# for av-install-*
CurrentVer()
{
    local -a vers
    if vers=(`olympusver -e -d`) && [[ ${#vers[@]} -eq 2 ]]; then
	engver=${vers[0]//[^0-9]}
	datver=${vers[1]//[^0-9]}
	return 0
    else
	engver=0 datver=0
	return 1
    fi
}

# wait an appropriate time for a retry
declare -i trydiv=MAXTIME/TRYWAIT done_tries=0
RetryPause()
{
    (( done_tries++ > max_rtry )) && return 1		# no more tries
    (( done_tries > 1 )) || return 0			# first time
    local -i pause=MAXTIME-SECONDS
    (( pause > 0 )) || return 1				# no more time
    (( trydiv > 1 )) && (( ( pause /= trydiv ) , trydiv /= 2 ))
    showstate "_WAIT_FOR_ $pause _WAIT_FROM_"
    ReportProgress _TR_ "update-sleep" $"sleeping %d before retry" $pause
    GoodEvent UpdateSleep -i SLEEP_TIME -v $pause
    SendLog "sleeping $pause before retry"
    sleep $pause || return 1
}

showstate "_STARTED_"

# make temp directory for all our files
rm -rf $tmp
mkdir -p $tmp &&
    cd $tmp || BadExit "creating tmp directory"

CurrentVer
SendLog "$me starting with engine $engver DATs $datver"
ReportProgress _TR_ "av_update_start" $"starting with engine %s DATs %s" \
    "$engver" "$datver"

if [[ -n "$server" ]]; then	# if we're fetching from a remote server
    GoodEvent UpdateNetwork -i COMMANDLINE -v "$cmdline"
    SendLog "server: $server" "path: $srcpath" \
	${proxy:+"proxy: $proxy${pport:+:$pport}"}
    # Keep trying until it works or it's time to give up
    SECONDS=0	# reset time
    while RetryPause; do

	# Fetch update.ini file
	showstate "_LOADING_"
	[[ -f update.ini ]] && mv update.ini update.ini.last
	GetFile -a update.ini $srcpath/update.ini || continue

	# Get the engine zip if we want it
	if $get_eng; then
	    # Extract latest engine data from update.ini
	    vals="$(ReadINI 'Engine-LINUX' eng)" && eval "$vals" || continue
	    eng_info=(\
		    -p SERVER -v "$server"\
		    -p DIRECTORY_NAME -v "$engFP"\
		    -p FILENAME -v "$engFN"\
		)
	    # Fetch engine zip file if we want it
	    if [[ "$engEV" -le "$engver" ]]; then
		showstate -e "_NOCHANGE_"
		SendLog "skipping engine - server has $engEV, we have $engver"
		unset eng_zip	# up to date - don't need it
	    elif GetZIP newengine.zip "$engver" "$engEV" \
		    "$engFN"  "$engFP" "$engFS" "$engMD"; then
		eng_zip=newengine.zip	# got it
	    else
		eng_zip=''	# want it, didn't get it
	    fi
	fi

	# Get the DAT zip if we want it
	if $get_dat; then
	    # Extract latest DAT data from update.ini
	    vals="$(ReadINI 'ZIP' dat)" && eval "$vals" || continue
	    dat_info=(\
		    -p SERVER -v "$server"\
		    -p DIRECTORY_NAME -v "$datFP"\
		    -p FILENAME -v "$datFN"\
		)
	    # Fetch DAT zip file if we want it
	    if [[ "$datDV" -le "$datver" ]]; then
		showstate -d "_NOCHANGE_"
		SendLog "skipping DATs - server has $datDV, we have $datver"
		unset dat_zip	# up to date - don't need it
	    elif GetZIP newdats.zip "$datver" "$datDV" \
		    "$datFN"  "$datFP" "$datFS" "$datMD"; then
		dat_zip=newdats.zip	# got it
	    else
		dat_zip=''	# want it, didn't get it
	    fi
	fi

	# try again?
	$get_eng && [[ -z "${eng_zip-unset}" ]] && continue
	$get_dat && [[ -z "${dat_zip-unset}" ]] && continue
	# we seem to have got what we want
	break
    done

else	# installing locally acquired files
    # not much useful to say about them
    GoodEvent UpdateLocal -i COMMANDLINE -v "$cmdline"
    SendLog "installing user supplied${eng_zip:+ engine}${dat_zip:+ DATs}"
fi

# sanity check
if [[ -n "$eng_zip" && ! -s "$eng_zip" ]]; then
    # bad eng_zip file
    BadEvent UpdateFileBad -i FILE_NAME -v "$eng_zip"
    SendLog "ERROR - no data in engine zip"
    eng_zip=''
fi
if [[ -n "$dat_zip" && ! -s "$dat_zip" ]]; then
    # bad dat_zip file
    BadEvent UpdateFileBad -i FILE_NAME -v "$dat_zip"
    SendLog "ERROR - no data in DAT zip"
    dat_zip=''
fi

# make really sure we're clean
rm -rf !("$eng_zip"|"$dat_zip")

# unpack engine
unset englist; declare -a englist
if [[ -n "$eng_zip" ]]; then
    if UnZip "$eng_zip" Engine eng englist; then
	if [[ ! -f eng/liblnxfv.so.4 ]]; then
	    ln -s liblnxfv.so eng/liblnxfv.so.4
	    englist[${#englist[@]}]='liblnxfv.so.4'
	fi
    else
	eng_zip=''
    fi
fi

if [[ -n "$eng_zip" ]]; then
    tldpath=$(pwd)/eng
else
    tldpath=$LD_LIBRARY_PATH
fi

# unpack DAT files
unset datlist; declare -a datlist
if [[ -n "$dat_zip" ]]; then
    mkdir -p dat
    # include any existing extra.dat if recent enough
    extras=$( [[ -s "$dat_dir/extra.dat" ]] &&
	find "$dat_dir/extra.dat" -type f -mtime -$EXTRA_KDAYS -print)
    if [[ -n "$extras" ]]; then
	cp -p "$extras" dat/.
    fi
    # unpack the zip
    UnZip "$dat_zip" DAT dat datlist || dat_zip=''
fi
if [[ -n "$dat_zip" ]]; then
    tdatdir=$(pwd)/dat
else
    tdatdir=$dat_dir
fi

# So in the end have we got something to install?
if [[ -z "$eng_zip" && -z "$dat_zip" ]]; then
    if [[ -n "${eng_zip-unset}" && -n "${dat_zip-unset}" ]]; then
	unset rep
	$get_dat && rep='DATs'
	$get_eng && rep="${rep:+$rep and }engine"
	GoodExit -e $NOCHevent::UpdateNoChange "$rep already up to date"
    else
	BadExit "Failed to update after $(( SECONDS/60 )) minutes trying"
    fi
fi

# Check what we got - does olympusver like it?
if out=$(LD_LIBRARY_PATH=$tldpath olympusver -D "$tdatdir" 2>&1) &&
    [[ -z "$out" ]]; then :
else
    BadEvent UpdateTestFail
    echo "$out"
    BadExit "Engine/DAT files loaded do not work - not installed"
fi

# get new engine and DAT versions
if vers=( $(LD_LIBRARY_PATH=$tldpath olympusver -e -d -D "$tdatdir") ) &&
	[[ ${#vers[@]} -eq 2 ]]; then
    engEV=${vers[0]//[^0-9]}
    datDV=${vers[1]//[^0-9]}
fi

ts=$(date +%Y-%m-%d_%T%Z)

RESTART=N
# Install engine
if [[ -n "$eng_zip" && ${#englist[@]} -gt 0 ]]; then
    ReportProgress _TR_ "install-engine" $"installing engine %s" $engEV
    SendLog "installing engine $engEV"
    /usr/sbin/webshield wsmount <<-END
	av-install-engine $eng_dir $ts ${englist[@]}
END
    if [[ $? -eq 0 ]] && CurrentVer
    then
	 GoodEvent UpdateEngine
         SendLog "installed engine $engEV OK"
         showstate -e "_DONE_"
	RESTART=Y
    else
	BadEvent UpdateEngineBadInst
        BadExit "Failed to install engine $engEV"
    fi
    exit_reason=UpdateEngine
fi

# Install DATs
if [[ -n "$dat_zip" && ${#datlist[@]} -gt 0 ]]; then
    ReportProgress _TR_ "install-av-dats" $"installing DATs %s" $datDV
    SendLog "installing DATs $datDV"
    echo "av-install-dat $dat_dir $datDV.$ts" | wsmount
    if [[ $? -eq 0 ]] && CurrentVer
    then
	GoodEvent UpdateDATs
        SendLog "installed DATs $datDV OK"
	RESTART=Y
    else
	BadEvent UpdateDATsBadInst
        BadExit "DATs $datDV install failed"
    fi
    if [[ $exit_reason == UpdateEngine ]]; then
	exit_reason=UpdateBoth
    else
	exit_reason=UpdateDATs
    fi
    
fi

# Go home
cd /tmp		# we're about to delete our $tmp
if [ $RESTART = Y ]
then
	/usr/sbin/webshield proxy-restart
fi
GoodExit ${exit_reason:+-e $CHNGevent::$exit_reason}

