#!/bin/sh

#############################################################
#
# Copyright (C) 2022 Musarubra US LLC.  All rights reserved.
#
# This script will install uvscan.
#
#############################################################

# Default installation location
default_dir="/usr/local/uvscan"
export default_dir

# Default install switches
switches="--secure -vr --summary"
swtch_install="--install"
all_fs="/"

# Displays error messages and quits.
# $1 - optional error message.
exit_error()
{
    [ -n "$1" ] && printf "$1\n"
    printf "Installation incomplete\n"
    exit 1
}

# Display usage for the script.
# $1 - Script name
display_usage()
{
    printf "Usage: $1 [-y] [install_dir]\n"
    printf "\n"
    printf "  -y              Assume default answer to all questions\n"
    printf "  install_dir     Directory in which to install uvscan\n"
    printf "                  Default is $default_dir\n"
    printf "\n"
}

# Asks question, and waits for one of 2 responses
# $1 - Question text
# $2 - 1st response - default
# $3 - 2nd response
# $4 - default - either 1(1st response) or 2(2nd response). Anything else, no default
# Exit Status...
# 0 - 1st response chosen
# 1 - 2nd response chosen
get_yn()
{
    if [ -n "$no_questions" ]
    then
        [ "$4" = 2 ] && return 1
        return 0
    fi
    
    unset answer
    while [ -z "$answer" ]
    do
        if [ "$4" = "1" ]
        then
            default=$2
            printf "$1 [$2]/$3 "
        elif [ "$4" = "2" ]
        then
            default=$3
            printf "$1 $2/[$3] "
        else
            default=" "
            printf "$1 $2/$3 "
        fi
        
        read answer
        
        # Set the default and take the first letter
        answer=`echo "${answer:-"$default"}" | cut -c1 | tr [:upper:] [:lower:]`

        [ "$answer" = "$2" ] && return 0
        [ "$answer" = "$3" ] && return 1

        unset answer
    done
}

    
# Check the directory supplied. If it doesn't exist, create it
# $1 - Directory name
# Exit status...
# 0 - All OK. Exists
# 1 - Doesn't exist. User declined to create it.
# 2 - Doesn't exist. Can't create.
check_dir()
{
    # If it exists, exit now.
    ls -ad "$1" >/dev/null 2>&1 && return 0
    
    if get_yn "$1 doesn't exist. Create it?" "y" "n" 1
    then
        mkdir -p "$1" 2>/dev/null && return 0

        printf "Failed to create $1\n"
        return 2
    fi
    
    return 1
}

# Make a symbolic link to filename in directory
# $1 - filename
# $2 - link name
# Exit status...
# 0 - All OK. Link exists
# 1 - Error. Link not created.
make_link()
{
    name=`basename "$1"`
    link_dir=`dirname "$2"`
    
    link_name="$2"
    file_name="$1"
    
    if check_dir "$link_dir"
    then
        if ls -ad "$link_name" >/dev/null 2>&1
        then
            if get_yn "$link_name already exists. Overwrite?" "y" "n" 1
            then
                rm -f "$link_name" 2>/dev/null
            fi
        fi

        if ls -ad "$link_name" >/dev/null 2>&1
        then
            printf "Cannot overwrite $link_name\n"
            return 1
        fi

        if ln -s "$file_name" "$link_name" 2>/dev/null
        then
            return 0
        fi

        printf "Cannot create $link_name\n"
    fi

    return 1
}

# Copy a file to the relevent directory and make the necessary links.
# $1 - repository
# $2 - install directory
# $3 - filename
# $4 - list of mandatory links.
# $5 - list of directories to contain links.
# Exit Status
# 1 - File missing from repository.
# 2 - Copy failed.
# 3 - Something minor happened. (Link not created)
install_file()
{
    repository_file="$1/$3"
    inst_file="$2/$3"
    
    unset warning
    
    # Make sure the file exists
    [ ! -f "$repository_file" ] && return 1
    
    # If we are installing to the current directory, do not
    # copy the file to itself.
    if [ "$repository_file" != "$inst_file" ]
    then
        # Copy the file to the install directory
        cp "$repository_file" "$inst_file" 2>/dev/null
        [ $? -ne 0 ] && return 2
    fi

    # Set its permissions
    chmod $permissions "$inst_file"

    # Create any mandatory links to the file. These are all
    # contained to the install directory.
    if [ -n "$4" ]
    then
        for link in $4
        do
            make_link "./$3" "$2/$link"
            [ $? -ne 0 ] && warning="Yes"
        done
    fi

    # Create any links outside of the install directory. Note: If
    # any mandatory links were created, these are also created
    # to point to these links.
    if [ -n "$5" ]
    then
        for link_dir in $5
        do
            if get_yn "Do you want to create the link(s) to $3 in $link_dir" "y" "n" 1
            then
                make_link "$inst_file" "$link_dir/$3"
                [ $? -ne 0 ] && warning="Yes"
                
                # Create the mandatory links to this link.
                if [ -n "$4" ]
                then
                    for link in $4
                    do
                        make_link "./$3" "$link_dir/$link"
                        [ $? -ne 0 ] && warning="Yes"
                    done
                fi
            fi
        done
    fi
    
    [ -n "$warning" ] && return 3
    
    return 0
}

# Get the path which install-uvscan was executed from.
tmp=`dirname $0`
runpath=`(cd $tmp ; pwd -P)`

# Determine the platform and set library name and c++ runtime
PLATFORM=`uname -s`
export PLATFORM

libdata=""

case $PLATFORM in
    "SunOS")                    # Solaris
        # The library name will vary depending on the version of uvscan, so
        # read it from uvscan's dependancies.
        libraryname="libsunfv.so.4"
        ;;
    "HP-UX")                    # HP-UX
        case `uname -r | cut -c-4` in
            "B.10")             # A platform we do not support.
                    unset PLATFORM
                    ;;
            *)      libraryname="libhpxfv.4"
                    linkname="libhpxfv.sl"
                    ;;
        esac
        ;;
    "Linux")                    # Linux
        linkname="liblnxfv.so"
        libraryname="$linkname.4"
        ;;
    "FreeBSD")                  # FreeBSD
        libraryname="libbsdfv.so.4"
        linkname="libbsdfv.so"
        ;;
    "AIX")                      # AIX
        libraryname="libaixfv.a"
        linkname=""
        libdata="
        libstdc++.a,555,"",,
        libgcc_s.a,555,"",,
        uvscancore,555,"",,"
        ;;
    *)                          # A platform we do not support.
        unset PLATFORM
        ;;
esac

[ -z "$PLATFORM" ] && exit_error "Unknown platform. Unable to install."

# 
#  Check if we are on linux 64, in which case add 64 to lib directory.
#
suffix64=""
if [ $PLATFORM = "Linux" ]
then
    # Output from file ./uvscan ...
    # ./uvscan: ELF 64-bit LSB executable, AMD x86-64, version 1 (SYSV), for GNU/Linux 2.6.4, dynamically linked (uses shared libs), for GNU/Linux 2.6.4, stripped
    #  
    test64=`file $runpath/uvscan | awk '{ print $3 }' | cut -c-2`
    if [ $test64 = "64" ]
    then
    suffix64="64"
    fi
fi


# Files to install...
# filename, permissions, link to;
data="
config.dat,444,,
license.dat,666,,
readme.txt,444,,
cls703upg.pdf,444,,
license.txt,444,,
signlic.txt,444,,
uvscan,555,/usr/local/bin,
uvscan_secure,555,/usr/local/bin,
$libraryname,555,,
uninstall-uvscan,555,,
uvscan.1,444,/usr/local/man/man1,
$libdata"

uninstall="uninstall-uvscan"

# Gracefully exit if we get ^C'd
trap 'exit_error "\n"' 2

# Process any switches on the command line
unset no_questions
while getopts :y arguments
do
    case $arguments in
        y) no_questions="xxx" ;;
        *) display_usage `basename $0` ; exit ;;
    esac
done

# Remove all processed arguments from $@
shift `expr $OPTIND - 1`

# export no_questions so that get_yn function knows its value
export no_questions

# If there is more than one argument left, complain.
if [ $# -gt 1 ]
then
    display_usage `basename $0`
    exit_error
fi

# Set install_dir to default if dir not supplied as argument
if [ -n "$1" ]
then
    install_dir="$1"
else
    if [ -z "$no_questions" ]
    then
        printf "Which directory do you want to install into? [$default_dir] "
        read answer
    else
        unset answer
    fi
    install_dir=${answer:-$default_dir}
fi

# Make sure the install directory exists
if check_dir "$install_dir"
then :
else
    exit_error
fi

# Some sanity checks on $install_dir
[ ! -d "$install_dir" ] && exit_error "$install_dir exists, but is not a directory"
[ ! -w "$install_dir" ] && exit_error "Cannot write to $install_dir"

full_install_dir=`(cd "$install_dir" ; pwd -P)`
if [ "$full_install_dir" != "$runpath" ]
then
    # We're not trying to install to the same directory this script
    # is running from, so uninstall any previous version.
    if [ -f "$install_dir/$uninstall" ]
    then
        printf "Uninstalling previous version ... "
        if echo "y" | $install_dir/$uninstall > /dev/null 2>&1
        then
            printf "done.\n"
        else
            printf "unsuccessful. Continuing.\n"
        fi
        
        chmod 777 "$install_dir/$uninstall" 2>/dev/null
        rm -f "$install_dir/$uninstall" 2>/dev/null
    fi
fi

# Initialise variables
missing_package=0
missing_install=0

error_string="."

for record in $data
do
    fname=`echo $record | cut -d, -f1`
    permissions=`echo $record | cut -d, -f2`
    linkdirs=`echo $record | cut -d, -f3`
    links=`echo $record | cut -d, -f4`
    
    if [ -n "$fname" ]
    then
        install_file "$runpath" "$full_install_dir" "$fname" "$links" "$linkdirs"
        status=$?
        case $status in
            1)
                printf "$fname is missing from the package\n"
                missing_package=`expr $missing_package + 1`
                ;;

            2)
                printf "$fname did not copy correctly\n"
                missing_install=`expr $missing_install + 1`
                ;;

            3)
                error_string="d with errors."
                ;;
        esac
    fi
done
        

if [ "$missing_install" -gt 0 -o "$missing_package" -gt 0 ]
then
    printf "\n"
    [ "$missing_install" -gt 0 ] && printf "$missing_install files(s) were not installed correctly\n"
    [ "$missing_package" -gt 0 ] && printf "$missing_package files(s) were missing from the package\n"
    
    exit_error
fi

cd $install_dir ; "./uvscan" $swtch_install ; chmod 444 license.dat ;

printf "\nInstallation complete$error_string\n\n"
trap 2

if get_yn "Do you want to perform a scan of all filesystems" "y" "n" 2
then
    (cd $install_dir ; "./uvscan" $switches $all_fs)
fi

