#!/bin/ksh
# %U% %W% %E%
#
# Script to install UNIX-Connect components from a CD-ROM
#
#
###############################################################################

LiveRun=true			# true when running for real, false for test

Args=$*

# Change to root UXC folder on CD-Rom & get its absolute path

MyScript=`basename $0`		# To use in SU etc

cd `dirname $0`				# To root UXC folder on CD
ImageRoot=`pwd`				# Get its absolute path
MyScript=$ImageRoot/`basename $0`	# To use in SU etc

. ./common			# Wait, GetVersionAndRoot functions
. ./common2			# Error, fail, Input, Query, Select, Cpio functions

# Determine host characteristics

DoWhom()
{
  HostType=$1			# sun   | aix | hp  | lrx  | l9x | sx ...
  Processor=$2			# sparc | ppc | ??  | i386 | ...
  Unix=$3			# Vr4   | Vr3 | ??? | Vr4  | ...
}
DoWhom `./whom`

ImageCpioDir=$ImageRoot/binary/base/${HostType}${Processor}
ImageVersion=`cat $ImageRoot/binary/base/${HostType}${Processor}/Version`

_IFS=$IFS
IFS="\(\)"
set `id`
MyUserId="${2}"
IFS=$_IFS

MyHome=`eval echo "~${MyUserId}"`	# Typically /usr/rosi
UxcRoot=$MyHome/UXC			# Typically /usr/rosi/UXC
RCSDIR=/usr/RCS

# Determine the default Revision

NameToRoot $RCSDIR/Name
DefaultRevision=$Version

umask 022


###############################################################################
#
# SU - Re-enter this setup as specified user to run specified function
#
SU()
{
    User=$1; shift

    if [ "$User" == "$MyUserId" ]
    then
	$MyScript $*
	return $?
    fi

    if [ "$MyUserId" != "root" ]
    then
	[ $REALQUIET ] && fail "SU: User needs to be root to do this"
	printf "Please enter the $User password\n"
    fi

    # Take account of problems with trailing switches on su lines.

    case $HostType in
		
	lrx|l9x)
	su -- $User -c "$MyScript $*"	;;

	hp)
	printf "Password: " &&
	su $User -c "$MyScript $*"	;;

	*)
	su $User -c "$MyScript $*"	;;
    esac

    return $?
}


###############################################################################
#
# GetRevisions - Get $Revisions, list of Revisions loaded on host in ~rosi/uxc.
#		 Also set $DefaultRevision if possible.
#
GetRevisions()
{
    Revisions=""
    for Name in $UxcRoot/*/Name
    do
	if [ -r $Name ]
	then
	    Name=`dirname $Name`
	    Name=`basename $Name`
	    #set `grep "SW UNIX-Connect"  $Name`	# Eg. "SW UNIX-Connect T2.0.0.0 ..."
	    #Revisions="$Revisions $3"
	    Revisions="$Revisions $Name"
	fi
    done
}


###############################################################################
#
# ListRevisionsEx - list all available (loaded) Revisions.
#		    Leaves list in $Revisions
#
ListRevisionsEx()
{
    # Re-check the default version, we may have uninstalled the default version

    NameToRoot $RCSDIR/Name
    DefaultRevision=$Version

    GetRevisions
    printf "\n"
    if [ "$Revisions" == "" ]
    then
	printf "...There are no loaded Revisions...\n"
	return 1
    fi

    i=0
    for Revision in $Revisions
    do
	((i+=1))
	printf "\t%d. %s" $i $Revision
	if [ "$Revision" == "$DefaultRevision" ]
	then
	    printf "\t(Default)"
	elif grep $Revision /usr/RCS/v*/Name > /dev/null 2>&1
	then
	    printf "\t(Installed)"
	fi
	printf "\n"
    done

    return 0
}


###############################################################################
#
# ListRevisions - List all available (loaded) Revisions, with leading heading
#
ListRevisions()
{
    printf "The following Revisions are loaded:\n\n"
    ListRevisionsEx
}


###############################################################################
#
# SelectRevision - select $Revision from available Revisions
#
SelectRevision()
{
    while true
    do
	ListRevisionsEx || return $?	# List revisions, left in $Revisions
	printf "\nPlease select a Revision from above [1..%d / q]: " $i
	read REPLY
	[ "${REPLY#[Qq]}" == "" ] && return 1
	Revision=`echo $Revisions|cut -f${REPLY} -d' ' 2> /dev/null`
	[ "$Revision" != "" ] && break
    done

    return 0
}


########################################################################
#
# StopSMs - stop all session managers
#
StopSMs()
{
    Attempts=10
    while s=`ps -e | grep SMANAGER | grep -v grep | awk '{ print $1 }'` \
		&& [ -n "$s" ]
    do
	# Replace newline separators with spaces
	set $s
	s="$*"

	((Attempts-=1))
	if [ $Attempts -le 0 ]
	then
	    printf "Failed to stop all Northgate Session Managers\n"
	    break
	fi
	kill -2 $s
	sleep 1
    done

    if [ -z "$s" ]
    then
	printf "All Northgate Session Managers have been stopped.\n"
    fi
}


###############################################################################
#
# SysRemove - Remove system links to Revision, /usr/RCS, /etc, /usr/include etc
#	      This needs to be invoked as root using SU.
#
SysRemove() # (Mode RevisionPath)
{
    Mode=$1		# forcedelete/nodelete/querydelete
    RevisionPath=$2

    NumInstallations=`find /usr/RCS -name Name -type f -print|wc -l`

    [ ! -x $RevisionPath/Remove ] && fail "$RevisionPath/Remove does not exist."

    NameToRoot $RevisionPath/Name
    if [ "$Root" == "/usr/RCS" ] && [ $NumInstallations -gt 1 ]
    then
	printf "This pre-v2.0 'uninstall' will remove all installations.\n"
	Query "Do you want to continue" n ||
	    fail "Aborting uninstall."
    fi

    cd $RevisionPath

    Revision=`cat Version`
    ./Remove ||
	fail $? "Failed to uninstall $RevisionPath."

    printf "Revision $Revision has been uninstalled.\n"

    if [ ! -d /usr/RCS ]
    then
	printf "There are no remaining installations.\n"
	printf "Ensuring that there are no active session managers.\n"
	StopSMs
    fi

    cd ..	# To UXC

    if [ "$Mode" == "querydelete" ]
    then
	if Query "Would you like to delete the loaded Revision, $RevisionPath" n
	then
	    Mode="forcedelete"
        fi
    fi

    if [ "$Mode" == "forcedelete" ]
    then
	rm -rf $RevisionPath || fail $? "Cannot delete $RevisionPath."
	printf "Loaded Revision $RevisionPath has been deleted.\n"
    fi
    exit 0
}


###############################################################################
#
# RemoveRevision - Remove specified, or selected Revision, remove installation
#		   and possibly the image itself.
#
RemoveRevision() # (Mode {Revision})
{
    Mode=$1
    Revision=$2

    if [ "$Revision" == "" ]
    then
	printf "To uninstall one of the following Revisions:\n"
	SelectRevision ||
	{
	    printf "Remove Revision operation aborted.\n"
	    return
	}
    fi

    RevisionPath=${UxcRoot}/${Revision}

    if [ ! -d $RevisionPath ]
    then
	printf "Revision $RevisionPath does not exist.\n"
	return
    fi

    # Remove system links to Revision, & possibly Revision itself

    SU root SysRemove $Mode $RevisionPath || fail "$Revision was not removed."

    return 0
}


###############################################################################
#
# SysInstall - Install system links to Revision, /usr/RCS, /etc, /usr/include etc
#	       This needs to be invoked as root using SU.
#
SysInstall() # (RevisionPath)
{
    RevisionPath=$1
    [ ! -x $RevisionPath/Install ] && fail "$RevisionPath/Remove does not exist."

    NameToRoot $RevisionPath/Name
    if [ "$Root" == "/usr/RCS" ]
    then
	NumInstallations=`find /usr/RCS -name Name -type f -print|wc -l`
	if [ $NumInstallations != 0 ]
	then
	    printf "All existing installations must be uninstalled before\n"
	    printf "this pre-v2.0 $Version is re-installed\n"
	    fail "Aborting install of $Version"
	fi
    fi

    cd $RevisionPath
    ./Install ||
	fail $? "Failed to install $RevisionPath."
    exit 0
}


###############################################################################
#
# InstallRevision - install specified, or selected Revision
#
InstallRevision()
{
    Revision=$1

    if [ "$Revision" == "" ]
    then
	printf "To re-install one of the following Revisions:\n"
	SelectRevision ||
	{
	    printf "Install of Revision has been aborted.\n"
	    return
	}
    fi

    IRRevision=$Revision
    RemoveRelease  nodelete $IRRevision ||
    {
	printf "Existing $Version must be uninstalled before $IRRevision can be installed.\n"
	fail "Install of $IRRevision has been aborted."
    }

    Revision=$IRRevision
    RevisionPath=${UxcRoot}/${Revision}

    if [ ! -d $RevisionPath ]
    then
	printf "Revision $RevisionPath does not exist.\n"
	return
    fi

    # Install system links to Revision

    SU root SysInstall $RevisionPath || fail "Revision $Revision was not installed."

    printf "Revision $Revision has been installed.\n"
    printf "\n\n*** YOU WILL NEED TO REBUILD REALITY ***\n\n"
    sleep 1

    return 0
}


###############################################################################
#
# RemoveRelease - if release already installed optionally remove it
# Return false (1) if release is installed & we didn't remove it
#
RemoveRelease() # (Version)
{
    Mode=$1
    MyVersion=$2
    VersionToRelease $MyVersion
    if [ -r ${RCSDIR}/v${Release}/Name ]
    then
	NameToRoot ${RCSDIR}/v${Release}/Name
	printf "Existing revision ${Version} needs to be uninstalled.\n"
	if Query "Do you want to uninstall revision ${Version}" y n
	then
	    RemoveRevision $Mode $Version
	else
	    return 1	# Release is installed, it was not removed
	fi
    fi
    return 0
}

###############################################################################
#
# InstallRevisionImage - load Revision image and install it
#
InstallRevisionImage()
{
    LoadRevisionImage
    InstallRevision $ImageVersion
}


###############################################################################
#
# LoadRevisionImage - just load Revision image, don't install
#
LoadRevisionImage()
{
    RemoveRelease querydelete $ImageVersion ||
    {
	printf "$Version must be uninstalled before $ImageVersion can be installed.\n"
	fail "Install of $ImageVersion has been aborted."
    }

    UxcRevisionPath=$UxcRoot/$ImageVersion
    if [ -d $UxcRevisionPath ]
    then
	printf "Directory $UxcRevisionPath must be removed.\n"
	if Query "Do you want to remove Revision $ImageVersion" y
	then
	    RemoveRevision forcedelete $ImageVersion
	else
	    fail "Install of $ImageVersion has been aborted."
	fi
    fi

    [ -d $UxcRevisionPath ] &&
	fail "Directory $UxcRevisionPath still exists, aborting installation."
    
    mkdir -p $UxcRevisionPath	# Now create it ready for cpio

    cd $UxcRevisionPath || fail "Cannot access $UxcRevisionPath."

    CpioOpts=-dicBum
    Cpio $ImageCpioDir		# Will exit on failure
    printf "Revision $ImageVersion has been loaded to $UxcRevisionPath.\n"
}


###############################################################################
#
# ChangeUserId - change UNIX user ID
#
ChangeUserId()
{
    Input "Enter the new user ID" rosi rosi
    case $REPLY in
	q|Q)	printf "User ID not changed."
		return 0;;
    esac

    SU $REPLY
    exit
}


###############################################################################
#
# Menu - run menu, inputting and processing requests
#
Menu()
{
    while true
    do
	# cd $ImgUxc -- DaveS, don't know intention here, not defined anywhere
	printf "\nUNIX-Connect: $ImageRoot\n"
	printf "Version: $ImageVersion  UserID: $MyUserId\n\n"
	if [ "$MyUserId" != "rosi" ]
	then
	    printf "        !!!! WARNING - you are not rosi !!!!\n\n"
	fi
	printf "  a)	Load & install the Revision Image $ImageVersion\n"
	printf "  b)    Just load the Revision Image $ImageVersion (Engineers only)\n"
	printf "  c)	Install/re-install a selected Revision\n"
	printf "  d)	Uninstall & delete a selected Revision\n"
	printf "  l)	List available (loaded) Revisions\n"
	printf "  u)	Change user ID\n"
	printf "  s)	Shell out\n"
	printf "  q)	Quit\n\n"

	ls /usr/RCS/v*/Name 1> /dev/null 2>&1 &&
	{
	    printf "\n"
	    printf "There are previous installations of UNIX-Connect. You should normally\n"
	    printf "uninstall and delete these with option 'd' before a new installation.\n\n"
	}

	printf "Please select an operation from above: "
	read REPLY
	printf "\n"

	case $REPLY in
	    a|A)	InstallRevisionImage;		Wait "";;
	    b|B)	LoadRevisionImage;		Wait "";;
	    c|C)	InstallRevision;		Wait "";;
	    d|D)	RemoveRevision querydelete;	Wait "";;
	    l|L)	ListRevisions;			Wait "";;
	    u|U)	ChangeUserId;			Wait "";;
	    s|S)	ksh -o emacs;			Wait "";;
	    q|Q)	exit 0;;
	esac
    done
}


###############################################################################
#
#				MAINLINE CODE
#
###############################################################################

if [ "$Args" != "" ]
then
    # Invoked, probably as SU, to call function
    eval $Args || fail $? "$Args failed $?"
    exit 0
fi

[ "$MyUserId" == "root" ] && fail "You cannot run this script as 'root'"

# Ensure ~rosi has read/exec for all so all users can access executables & libraries

chmod 755 $MyHome || fail "Unable to access $MyHome"

# Ensure that the base directory for Revisions exists

if [ ! -d $UxcRoot ]
then
    printf "Creating new $UxcRoot directory for Revisions.\n"
    mkdir $UxcRoot || fail $? "Unable to create $UxcRoot"
fi

Menu
