#!/bin/ksh -p
# Copyright (c) 1999-2000 by Sun Microsystems, Inc.  All Rights Reserved
#
# @(#)utdtsession.sh	1.47   00/05/05     SMI
#
# Script to add an X server to the Xservers file and set it up via the
# Xconfig file to service the session ID given as argument 1
#
# The database of available display numbers is taken as 
# Xservers. If a display is mentioned as
#
#	sysname:num OR :num
#
# at the beginning of a line or the beginning of a comment, it is considered
# unavailable for use.
#
# E.g. a line '# :3 RESERVED' will prevent display 3 from being assigned
#

ME=$0

verbose=0
umask 0022

# XXX Running pkginfo can be a performance hit. Should fix th value of
# XXX BASE at install time.
BASE=`pkginfo -r SUNWuto 2>/dev/null`
SUNWUT=$BASE/SUNWut
SUNWUTLIB=$SUNWUT/lib

libdir=$SUNWUTLIB

# Directory for the Prototype files for utdtrepair
PROTODIR=$SUNWUT/lib/prototype

# Set up the list of args for the utdtrepair command 
FILEFIX=" -d ${PROTODIR} -f /usr/dt/config/Xstartup"
FILEFIX="${FILEFIX} -f /usr/dt/config/Xsetup"
FILEFIX="${FILEFIX} -f /usr/dt/config/Xreset"
FILEFIX="${FILEFIX} -f /usr/openwin/server/etc/OWconfig"
FILEFIX="${FILEFIX} -f /etc/inet/services"
FILEFIX="${FILEFIX} -f /etc/inet/inetd.conf"

# Type can be "normal" which means dtlogin, or "special"
type="normal"
# Session type is one of the session types in the sessionTypes.props file
SESSION_TYPE="default"

XSUN="/usr/openwin/bin/Xsun"
XSUNFLAGS="-nobanner -terminate -dev /dev/sunray"
XINIT="$SUNWUTLIB/utxinit"

INET_SERVICES=/etc/inet/services 

#
# Set default values
#
INFODIR=/var/opt/SUNWut
ETCDIR=/etc/opt/SUNWut

set -u	# All vars must be set from now on

#
# Set defaults
#
MINDISP=2		# minimum display number XXX 
MAXDISP=1000		# maximum display number XXX -> must match OWconfig
dir=/tmp/SUNWut/config/xconfig # X-Windows configuration directory
xconfiglock=$dir/config.lock	# X-Windows config lock file
sid=""			# required parameter
tid=""			# required parameter
rtid=""

function usage {
print "
Usage: $ME [-d dir] [-f lockfile] [-h max] [-l min]	\\
	[-p path] [-x dir] [-t token] [ -r rawtoken ] [-c sessionType] {add|delete}
Parameters:
 -c sessionType		# script must exist: /etc/opt/SUNWut/<stype>.start
 -d infoDir		# base directory for mapping databases (tokens, displays)
 -f lockfileName	# name of lock file for X-Windows config files
 -h maxDisplay		# highest display number (default=$MAXDISP)
 -l minDisplay		# lowest display number (default=$MINDISP)
 -p path		# debugging option to specify path to support progs
 -r rawtoken		# raw token name before auth processing
 -t tokenId		# token name
 -v			# verbose
 -x dtDirectory		# X-Windows configuration directory (default=$dir)

 add			# add an X display for this token
 delete			# remove the X display for this token
 "
exit 1
}

# Function to delete a session
function deleteSession {
	typeset xserv=$1	# dtlogin's Xservers file
	typeset xconf=$2	# dtlogin's Xconfig file
	typeset token=$3	# token name
	typeset tokenfile=$4	# token file containing session ID
	typeset lockfile=$5	# X config lock file

	#
	# Remove the display file on success -> this must be atomic
	# because the display number may be reassigned immediately
	#
	# We can remove the token file later because we hold the token
	# lock throughout
	#

	typeset rmdisplay="$SUNWUTLIB/utrmdpy "'$UT_DPY'

	$libdir/utdtutil -l $lockfile -D "_TOKEN=$token\>" -r "$rmdisplay" \
		$xserv $xconf > /dev/null

	/bin/rm -f $tokenfile
}

# Function to establish user connection authentication for an X display
function xauthDisplay {
        typeset dpy=$1
        typeset cookie_dir="/tmp/SUNWut/config/xauth"
        typeset cookie_path="$cookie_dir/cookie:$dpy"
        typeset xmkcookie="/usr/openwin/lib/mkcookie"

        if [ ! -r $cookie_path -a -x "$xmkcookie" ]
        then
                [ ! -d "$cookie_dir" ] && /bin/mkdir -p $cookie_dir
                $xmkcookie $cookie_path -auth magic-cookie 2>&1 > /dev/null
        fi

        # OK to enable X server authentication
        if [ -r $cookie_path ]
        then
                # Make the cookie and database the same file
                export XAUTHORITY=$cookie_path
                XSUNFLAGS="$XSUNFLAGS -auth $cookie_path"
        fi
}

#
# Parse and validate command line options
#
if (( $# == 0 ))
then
	usage
fi

while getopts :c:d:f:h:l:p:r:t:vx: name
do
	case $name in
	(c)	SESSION_TYPE="$OPTARG";
		type=special;
		;;
	(d)	INFODIR="$OPTARG";;
	(f)	xconfiglock="$OPTARG";;
	(h)	MAXDISP="$OPTARG";;
	(l)	MINDISP="$OPTARG";;
	(p)	libdir="$OPTARG";;
	(r)	rtid="$OPTARG";;
	(t)	tid="$OPTARG";;
	(v)	verbose=$(($verbose + 1))
		exec 1>&- 2>&-
		exec 1>/tmp/utdt.$$ 2>&1
		;;
	(x)	dir="$OPTARG";;
	(?)	print -u2 Invalid option "'$OPTARG'";
		usage;;
	(:)	print -u2 Required option "'$OPTARG'" is missing;
		usage;;
	esac
done
shift $(expr $OPTIND - 1)

case $1 in
(add)
	action=add
	shift
	;;
(delete)
	action=delete
	sid=dont_care
	shift
	;;
(*)
	print -u2 "Invalid or missing action; {add|delete} required"
	usage
	;;
esac

# It is possible to pass arguments to type=special sessions run by XINIT
if [[ "${1:-}" == "--" ]]
then
	shift
	options="${@:-}"
else
	options=""
fi
# command line argument parsing is complete


# The following vars can be affected by command line arguments
libfile=$libdir/xdisplayutil
Xservers=$dir/Xservers
Xconfig=$dir/Xconfig
DBDIR=$INFODIR/tokens
DISPDIR=$INFODIR/displays
INSERTDIR=$INFODIR/itokens


# Get common support functions 
. $libfile


#
# Read parameters from stdin if they have not been fully specified already
#
# Passing parameters through the environment exposes them to world read.
# Do not export sid.
#
if [ -z "$sid" -o -z "$tid" ]
then
	while read expression
	do
		case $expression in
		("#"*)		# allow comment
			;;
		(CORONA_SESSION=*)
			if [ -z "$sid" ]
			then
				sid=${expression#CORONA_SESSION=};
			fi
			;;
		(TOKEN_IDENTITY=*)
			if [ -z "$tid" ]
			then
				tid=${expression#TOKEN_IDENTITY=};
			fi
			;;
		(INSERT_TOKEN=*)
			if [ -z "$rtid" ]
			then
				rtid=${expression#INSERT_TOKEN=};
			fi
			;;
		(*)	break	# quit on garbage or blank line
			;;
		esac
	done
fi

# Validate parameters
error=false
if [ -z "$sid" ]
then
	print -u2 'Missing session specification (-s option)'
	error=true
fi
if [ -z "$tid" ]
then
	print -u2 'Missing token specification'
	error=true
fi
if [ "$error" = "true" ]
then
	usage
fi

#
# Check for existing session
#

tif=$DBDIR/$(print $tid | tr '.' '/')
tiflock=$tif.lock

if [[ $verbose -gt 1 ]]; then print tif=$tif; fi
umask 0077
mkdir -p $(dirname $tif)/.
mkdir -p $(dirname $tiflock)/.
umask 0022
mkdir -p $DISPDIR/.
umask 0022

startlocks
trap endlocks 0 HUP INT TERM	# must be outside lock()

lock $tiflock $libdir/lockfile

if [ "$action" = "delete" ]
then
	deleteSession $Xservers $Xconfig $tid $tif $xconfiglock
	kill -HUP $(/bin/cat /var/dt/Xpid)	# tell dtlogin to reread config
	exit 0
fi


if [ -f $tif ]
then
	# A session is already configured.
	# If the session is compatible, then let it stand, else remove it
	# so that a new session can be created.

	# get the existing session ID
	oldsid=$(/usr/bin/head -1 $tif)

	# get the existing session type
	OLD_SESSION_TYPE=""
	dpy=$($libdir/utdtutil -l $xconfiglock -g "_TOKEN=$tid\>" \
		$Xservers $Xconfig)
	if [[ -n "$dpy" && -f $DISPDIR/$dpy ]]
	then
		# Set the modified time on the display file for use by
		# the group manager to decide which server owned this
		# token last.
		/bin/touch $DISPDIR/$dpy

		OLD_SESSION_TYPE=$(grep '^SESSION_TYPE=' $DISPDIR/$dpy)
		OLD_SESSION_TYPE=${OLD_SESSION_TYPE#SESSION_TYPE=}
	fi
		
	if [[ "$sid" != "$oldsid" || "$SESSION_TYPE" != "$OLD_SESSION_TYPE" ]]
	then
		#
		# The token is already in use with session $oldsid.
		# delete the old dtsession and create a new one.
		#
		deleteSession $Xservers $Xconfig $tid $tif $xconfiglock
	else
		# XXX It should be that since the configuration did not
		# change, we should not need to bother dtlogin.  However,
		# during testing, there was at least one case where the
		# kill was needed.  So, the kill remains.
		kill -HUP $(/bin/cat /var/dt/Xpid)
		exit 0
	fi
fi

#
# Add a session
#

xcdesc="Dtlogin.*_%d.environment: CORONA_TOKEN=$tid"
if [ "$type" = normal ]
then
	xsdesc=":%d SunRay local@none /usr/openwin/bin/Xsun :%d -nobanner"
else
	xsdesc="# :%d RESERVED"
fi

# save mapping of token to session
# into a temporary "displays" file and move into place on success
umask 0177 
TMPD=$DISPDIR/.tmp.$$
print "SESSION=$sid\nTOKEN=$tid\nSESSION_TYPE=$SESSION_TYPE" > $TMPD

#
# Build the command to be run after display number is allocated but
# before updating the X configuration files
#
typeset mvdisplay='/bin/echo DISPLAY=$UT_DPY >> '"$TMPD"
typeset mvdisplay="$mvdisplay; /bin/mv $TMPD $DISPDIR/"'$UT_DPY'

typeset filefix="$SUNWUTLIB/utdtrepair $FILEFIX"
#
# Allow everyone to read Xsessions and Xconfig file
#
umask 0022

dpy=$($libdir/utdtutil -l $xconfiglock -s "$xsdesc" -c "$xcdesc" \
	-i "$INET_SERVICES" -F $MINDISP -L $MAXDISP \
	-R "$mvdisplay" -r "$filefix" $Xservers $Xconfig)

if [ $? -ne 0 -o -z "$dpy" -o "$dpy" -lt 0 ]
then
	print "Error: No display numbers available"
	# no need to bother dtlogin, no change could be made
	/bin/rm -f $TMPD
	exit 2
fi

# save mapping of token to session
umask 0177 
print $sid > $tif

# Link $INSERTDIR/$rtid to $DISPDIR/$dpy if $rtid is defined.
if [ -n "$rtid" ]
then
	print "INSERT_TOKEN=$rtid" >> $DISPDIR/$dpy
	/bin/rm -f $INSERTDIR/$rtid
	/bin/ln $DISPDIR/$dpy $INSERTDIR/$rtid
fi

# allow group 'root' to read this (for Xsun)
/bin/chgrp root $DISPDIR/$dpy
/bin/chmod g+r $DISPDIR/$dpy
umask 0022
if [ "$type" != normal ]
then
	#
	# Fix our priority back to normal
	# (raised in /etc/init.d/utsvc).
	#
	/bin/priocntl -s -c TS -p 0 $$

	if /usr/xpg4/bin/grep -q '^## utdtsession no-xinit' \
	    $ETCDIR/$SESSION_TYPE.start
	then
		($ETCDIR/$SESSION_TYPE.start $tid $options) &
	else
		xauthDisplay $dpy
		($XINIT $ETCDIR/$SESSION_TYPE.start $tid $options --\
		    $XSUN ":$dpy" $XSUNFLAGS) &
	fi
	# We do not keep track of child.
fi

kill -HUP $(/bin/cat /var/dt/Xpid)	# tell dtlogin to reread config
exit 0
