#! /bin/sh ## Usage: xrsh clientmachine [ -l username ] [ Xcommand [ args ]] ## This is similar to the standard "rsh" command, but for X programs. ## Runs Xcommand (defaults to "xterm") remotely on the client ## machine with the given name, displaying on X server determined by ## the current DISPLAY environment variable, with TERM set to "xterm". ## If DISPLAY is not set, or is incomplete, the necessary pieces are ## filled in from the default value of ":0.0". Optional "-l ## username" arguments are passed to rsh. If the command is "xterm", ## then it adds "-n 'xterm @ '" args. Runs xhost on the ## server machine if server is different than client and XRSH_NOXHOST ## is unset. If environment variable XDEBUG is unset, errors go to ## dev/null. If XDEBUG is set to null, status messages are sent to ## stdout. Otherwise, assumes XDEBUG is a filename to which status ## messages are appended. Attempts not to leave any processes waiting ## (on either machine) for the client to exit: uses exec where ## possible, and tries to prevent rsh from waiting for input. Uses ## /bin/csh on the remote host to get around user's shell. ## Things that commonly go wrong: ## - host must be in user's .rhosts file on server (to allow rsh for xhost). ## - "xhost" must be in your path on server (should set $path in .cshrc). ## - host must be in user's .rhosts file on client (to allow rsh for Xcommand). ## - Xcommand must be in your path on client (should set $path in .cshrc). ## where: host = machine from which xrsh is run, server = machine ## running X, client = machine that will run X program. ## Caveats: 1) This is a sh script, but uses csh on the remote ## machine. 2) Still leaves extra processes around sometimes. THis ## is hard to get rid of on all machines. 2) If XDEBUG is a filename, ## the xrsh process must remain alive to receive error messages (maybe ## we could avoid this by sending messages to a temp file, and then ## cat'ing them back to the host machine when the X command exits). ## 3) Runs (possibly) unecessary xhost commands, but this is hard to ## avoid. ## Suggestions: 1) Might be nice if this could parse the .rhosts file ## to get a default username and full clientname. 2) Maybe we should ## scrap the xhost stuff altogether, and assume the user has run a ## command to call xhost on each machine in the .rhosts file! The ## correct answer is to use xauth. ## Written 1/91 by Eero Simoncelli, , ## with help from Martin Friedman . ## Based on versions by Jim Dempsey and Martin Friedman. ## Usage message if [ $# = 0 ]; then echo "Usage: `basename $0` clientmachine [ -l username ] [ Xcommand [ args ]]" exit 1 fi ## Send messages and error output to /dev/null by default, thus ## allowing the script to terminate. If XDEBUG is set to nothing, ## send output to sdout (script process will remain, awaiting output). ## Else assume XDEBUG is a filename and append errors to this file ## (again, script process will remain, awaiting output). case "x${XDEBUG-NODEBUG}" in xNODEBUG) debugsh="> /dev/null 2>&1" debugcsh=">& /dev/null" ;; x) debugsh= debugcsh= ;; x*) debugsh=">> $XDEBUG 2>&1" debugcsh=">>&! $XDEBUG" ;; esac ## Get client machine name, and current (host) machine names client="$1"; shift host=${HOST-`/bin/hostname`} ## Get (optional) username if [ x$1 = x"-l" ] ; then user="$1 $2"; shift 2 else user= fi ## Set up command if [ $# -ge 1 ]; then command=$1; shift else command="xterm" fi ## Grab rest of args, since will lose them below when using the IFS args=$@ ## Hold onto original Internal Field Specifier oldIFS=$IFS ## Set up shortened client and host names. Fast parsing using the IFS. IFS="${oldIFS}." set - $client; sclient=$1 set - $host; shost=$1 IFS=$oldIFS ## If command is xterm, add title string arg to args if [ "$command" = "xterm" ]; then args="-n 'xterm @ $sclient' $args" fi ## Set up display, defaulting to ${host}:0.0 case "x$DISPLAY" in x) echo "DISPLAY variable not set. Assuming $host:0.0" display="${host}:0.0" ;; x:*) display="${host}${DISPLAY}" ;; xunix:*) IFS="${oldIFS}:"; set - $DISPLAY; display="${host}:$2"; IFS=$oldIFS ;; x*:) display="${DISPLAY}0.0" ;; x*) display="$DISPLAY" ;; esac ## Determine if display machine (server) is same as host machine case "x$DISPLAY" in x|x:*|xunix:*) serverishost=1 ;; x*) IFS="${oldIFS}:"; set - $DISPLAY; server=$1 IFS="${oldIFS}."; set - $server; sserver=$1; IFS=$oldIFS if [ $sserver = $shost ] ; then serverishost=1 else serverishost=0 fi ;; esac ## Redirect all subsequent input and output eval "exec < /dev/null $debugsh" ## If debugging, then echo some status lines: if [ "x${XDEBUG-NODEBUG}" != "xNODEBUG" ] ; then echo "EXECUTING $command $args" if [ "$user" = "" ] ; then echo " ON CLIENT $client" else echo " ON CLIENT $client, AS USER $user" fi echo " FROM HOST $host, ON DISPLAY $display" fi ## If client is not the same as server, and XRSH_NOXHOST is unset, run ## xhost. if [ "x${sclient}" != "x${sserver}" ] ; then if [ "x${XRSH_NOXHOST-doit}" = "xdoit" ] ; then if [ $serverishost = 1 ] ; then DISPLAY=$display; export DISPLAY; xhost +$client < /dev/null else rsh $server $user -n "exec /bin/csh -c \ \"setenv DISPLAY $display; xhost +$client\" < /dev/null" fi fi fi ## Execute command on client, using exec to avoid spawning extra ## processes. Use /bin/csh to get around the user's shell. If no ## debugging messages will be passed back, let the rsh ## process exit immediately by sending the /bin/csh output to ## /dev/null. if [ "x${XDEBUG-NODEBUG}" = "xNODEBUG" ] ; then exec rsh $client $user \ "exec /bin/csh -c \ \"setenv DISPLAY $display; setenv TERM xterm; exec $command $args &\" \ < /dev/null >& /dev/null" else exec rsh $client $user -n \ "exec /bin/csh -c \ \"setenv DISPLAY $display; setenv TERM xterm; exec $command $args \" \ " fi exit 0