#!/bin/sh # xon --- run remote X application # Copyright (C) 1993, 95, 99, 2002 Noah S. Friedman # Author: Noah Friedman # Created: 1993-03-08 # $Id: xon,v 1.11 2002/08/27 02:24:49 friedman Exp $ # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, you can either send email to this # program's maintainer or write to: The Free Software Foundation, # Inc.; 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA. # Commentary: # Code: # Name by which this script was invoked. fullprogname=$0 progname=`echo "$0" | sed -e 's/[^\/]*\///g'` bq='`' eq="'" usage="Usage: $progname {options} [rhost] [cmd] {args...} Options are: -D, --debug Turn on shell debugging (${bq}set -x$eq). -d, --display DISP Set DISPLAY environment variable to DISP. -e, --export VAR Export current definition of environment V,V1,... variable VAR on remote host. If multiple, comma-separated variables are specified, export the value of each one. This option can also be specified multiple times, once for each variable. -h, --help You're looking at it. -l, --login-as USER Log in as USER on remote host. -r, --rsh RSHCMD Use RSHCMD to connect to remote host. Defaults to remsh or rsh depending on system. -X, --xauth Transmit xauth authentication information. -x, --xhost-enable XHOST Use ${bq}xhost$eq to enable X server access for host XHOST. " # Make sure stdout and stderr are readable; if not # on a terminal, then in a file. for fd in 1 2; do if test ! -t $fd ; then # Redirect in append mode, in case the file is already there with # previous output. eval exec "$fd>>" ${XONERRORFILE-$HOME/.xon-errors} fi done # Usage: eval "$getopt"; value=$optarg # or optarg_optional=t; eval "$getopt"; value=$optarg # # This function automatically shifts the positional args as appropriate. # The argument to an option is optional if the variable `optarg_optional' # is non-empty. Otherwise, the argument is required and getopt will cause # the program to exit on an error. optarg_optional is reset to be empty # after every call to getopt. The argument (if any) is stored in the # variable `optarg'. # # Long option syntax is `--foo=bar' or `--foo bar'. 2nd argument # won't get used if first long option syntax was used. # # Note: because of broken bourne shells, using --foo=bar syntax can # actually screw the quoting of args that end with trailing newlines. # Specifically, most shells strip trailing newlines from substituted # output, regardless of quoting. getopt=' { optarg= case "$1" in --*=* ) optarg=`echo "$1" | sed -e "1s/^[^=]*=//"` shift ;; * ) case ${2+set} in set ) optarg="$2" shift shift ;; * ) case "$optarg_optional" in "" ) case "$1" in --*=* ) option=`echo "$1" | sed -e "1s/=.*//;q"` ;; * ) option="$1" ;; esac exec 1>&2 echo "$progname: option $bq$option$eq requires argument." echo "$progname: use $bq--help$eq to list option syntax." exit 1 ;; esac ;; esac ;; esac optarg_optional= }' # Initialize variables. # Don't use `unset' since old bourne shells don't have this command. # Instead, assign them an empty value. debug= close_stdfds=t explicit_display= export_vars= rshcmd= xauthinfo= xhost_enable_host= # Parse command line arguments. # Make sure that all wildcarded options are long enough to be unambiguous. # It's a good idea to document the full long option name in each case. # Long options which take arguments will need a `*' appended to the # canonical name to match the value appended after the `=' character. while : ; do case $# in 0) break ;; esac case "$1" in -D | --debug | --de* ) set -x debug=-x shift ;; -d | --display* | --di* ) explicit_display=t eval "$getopt" DISPLAY=$optarg ;; -e | --export* | --e* ) eval "$getopt" var=$optarg case "$var" in *,* ) var=`echo "$var" | sed -e 's/,/ /g'` ;; esac for v in $var ; do case " $export_vars " in *" $v "* ) : ;; * ) export_vars="$export_vars $v" ;; esac done ;; -l | --login-as* | --l* ) eval "$getopt" USER=$optarg ;; -h | --help | --h ) echo "$usage" 1>&2 exit 1 ;; -r | --rsh* | --r* ) eval "$getopt" rshcmd="$optarg" ;; -X | --xauth | --xa* ) shift xauthinfo=t ;; -x | --xhost-enable* | --xh* ) eval "$getopt" xhost_enable_host=$optarg ;; -- ) # Stop option processing shift break ;; -? | --* ) case "$1" in --*=* ) arg=`echo "$1" | sed -e 's/=.*//'` ;; * ) arg="$1" ;; esac exec 1>&2 echo "$progname: unknown or ambiguous option $bq$arg$eq" echo "$progname: Use $bq--help$eq for a list of options." exit 1 ;; -??* ) # Split grouped single options into separate args and try again optarg="$1" shift set fnord `echo "x$optarg" | sed -e 's/^x-//;s/\(.\)/-\1 /g'` ${1+"$@"} shift ;; * ) break ;; esac done case $# in 0 | 1 ) echo "$usage" 1>&2 exit 1 ;; esac USER=${USER-${LOGNAME-`{ id | sed -ne 's/.*uid=[0-9]*(// s/).*// p' } \ || { (whoami) 2> /dev/null; }`}} export USER rhost=$1 shift { hostname=`hostname 2> /dev/null` case "$hostname" in *.* ) : ;; * ) # Try to use DNS to resolve the hostname. if (perl -v > /dev/null) 2> /dev/null; then name=`perl -e '($name) = gethostbyname ($ARGV[0]); print "$name\n";' "$hostname"` case "$name" in *.* ) hostname="$name" ;; esac else # Note that if this is done the result could be incorrect. # "domainname" is actually supposed to return the NIS domain rather # than the domain of the host, but many system administrators # configure systems incorrectly. If `hostname' doesn't return the # fully-qualified domain name, gripe at your sysadmin today! domainname=`(dnsdomainname) 2> /dev/null || domainname` hostname="$hostname.$domainname" fi ;; esac hostname_unqualified=`echo "$hostname" | sed -e 's/\..*//'` } # canonicalize DISPLAY if not explicitly declared on the command line { case "$explicit_display" in t ) : ;; * ) # If DISPLAY isn't already set, then we really don't know the display. # Assume :0.0 on current host. case "$DISPLAY" in '' ) DISPLAY=$hostname:0.0 export DISPLAY ;; * ) display_number=`echo "$DISPLAY" | sed -e 's/.*://'` display_host=`echo "$DISPLAY" | sed -e 's/:[^:]*//'` # This will only happen if there's no display number in the first # place. case "$display_number" in "$display_host" ) display_number=0.0 ;; esac # Try to guess intelligently whether display host should be reset # (e.g., if it's a hostname that's not local, then it's probably # accurate and we shouldn't clobber it by setting it to the local # host) case "$display_host" in unix | loopback | localhost | '' ) display_host=$hostname ;; $hostname_unqualified ) display_host=$hostname ;; *.* ) : ;; * ) # Try to use DNS to resolve the FQDN. if (perl -v > /dev/null) 2> /dev/null; then name=`perl -e '($name) = gethostbyname ($ARGV[0]); print "$name\n";' "$display_host"` case "$name" in *.* ) display_host="$name" ;; esac fi ;; esac DISPLAY=$display_host:$display_number export DISPLAY ;; esac ;; esac } # Enable access via xhost, if necessary. # The xhost in some later versions of X11 (X11R6) refuse to accept # connections to any display other than the local display number # (e.g. ":0.0" or ":1.0", but not "foo:0.0" even if xhost is run on foo). # So munge the display appropriately. # # This calls this script recursively (sans the --xhost-enable option) to # do the whole path searching and exporting frobs implemented below. { case "$xhost_enable_host" in '' ) : ;; * ) # usage: xhost_args="arguments..."; eval "$do_xhost" # Then inspect value of $xhost_msg. do_xhost=' { xhost_msg=` xhost $xhost_args 2>&1 \ | sed -ne '\'' /access control disabled/{s/.*/win/p;q;} /^'\''"$xhost_enable_host"'\''$/{s/.*/win/p;q;} /connection to .* refused by server/{s/.*/refused/p;q;} /must be on local machine/{s/.*/refused/p;q;} /added to access control list/{s/.*/added/p;q;} /removed from access control list/{s/.*/removed/p;q;} $s/.*/unauthorized/p '\'' ` }' xhost_args=; eval "$do_xhost" case "$xhost_msg" in unauthorized ) xhost_args=$xhost_enable_host eval "$do_xhost" ;; esac case "$xhost_msg" in win | added ) : ;; refused ) display_host=`echo "$DISPLAY" | sed -e 's/:[^:]*//'` display_number=`echo "$DISPLAY" | sed -e 's/.*:/:/'` "$fullprogname" --display "$display_number" \ -- \ "$display_host" xhost "$xhost_enable_host" ;; esac ;; esac } { # Construct the export variable string that gets evaluated in the rsh # subshell. export_var_string= case "$export_vars" in '' ) export_var_string= ;; * ) for var in $export_vars; do # You are not expected to understand this. str=$var=\'`eval echo \"\\$$var\"`\'';' export_var_string="$export_var_string $str" done export_var_string="$export_var_string export $export_vars" ;; esac # Standard global places that ought to go in path pdirs=' /opt/lude/bin /opt/local/bin /usr/local/gnu/bin /usr/local/gnubin /usr/local/gnu /usr/local/bin /gnu/bin /lusr/gnu/bin /lusr/bin/gnu /usr/site /bin /usr/bin /usr/ucb /usr/local/etc /usr/etc /etc /usr/local/sbin /usr/sbin /sbin /usr/libexec /usr/lib ' # Places where X binaries might reside # These will appear in PATH *after* those listed in $pdirs. xdirs=' /usr/X11R6/bin /usr/X11R5/bin /usr/X11R4/bin /usr/bin/X11R6 /usr/bin/X11R5 /usr/bin/X11R4 /usr/local/X11R6/bin /usr/local/X11R5/bin /usr/local/X11R4/bin /usr/local/bin/X11R6 /usr/local/bin/X11R5 /usr/local/bin/X11R4 /usr/X11/bin /usr/bin/X11 /usr/local/X11/bin /usr/local/bin/X11 /usr/openwin/bin /usr/openwin/share/bin /usr/dt/bin /usr/X386/bin /usr/x386/bin /usr/XFree86/bin/X11 /usr/bin /usr/local/bin /usr/unsupported/bin /usr/athena/bin /usr/local/x11r5/bin /usr/lpp/Xamples/bin ' case "$rshcmd" in '' ) # Use rsh instead of remsh if the former exists rsh=remsh for d in `echo $PATH | sed -e 's/^:/.:/;s/::/:.:/g;s/:$/:./;s/:/ /g'` do if test -f "$d/rsh" ; then rsh=rsh break fi done ;; * ) rsh="$rshcmd" ;; esac remote_display=\${DISPLAY-\"$DISPLAY\"} # Be sure to close various file descripters so that lusing rshds wont # inherit them. (6, 7, 8, and 9 show up under various operating # systems where rshd hasn't been fixed). # # The "xauth remove" is theoretically unnecessary below, but due to a bug # in the initial X11R5 (through at least fix-03) xauth, entries for # MIT-MAGIC-COOKIE-1 get lost if you do merge twice without the remove. { # This must be in a separate test because the test below runs in a # subshell, and changes in that environment won't affect this process. case "$rshcmd" in ssh-x11 ) close_stdfds= ;; esac { case "$rshcmd" in ssh-x11 ) exec ssh -o 'ForwardX11 yes' -l "$USER" "$rhost" sh $debug ;; ssh | */ssh ) exec $rsh -x -l "$USER" "$rhost" sh $debug ;; * ) exec $rsh -l "$USER" "$rhost" sh $debug ;; esac } <<__EOF__ $export_var_string case "$1" in /* | ./* ) : ;; * ) for dir in `echo $pdirs $xdirs` ; do if test -f "\$dir/$1" || test -f "\$dir/xauth"; then PATH="\$PATH:\$dir" fi done export PATH ;; esac DISPLAY=$remote_display export DISPLAY case '$XUSERFILESEARCHPATH' in '' ) : ;; * ) XUSERFILESEARCHPATH='$XUSERFILESEARCHPATH' export XUSERFILESEARCHPATH ;; esac case '$XAUTHORITY' in '' ) : ;; * ) if test -f '$XAUTHORITY'; then XAUTHORITY='$XAUTHORITY' export XAUTHORITY fi ;; esac case '$xauthinfo' in t ) xauth -q remove $remote_display echo '`xauth -q nextract - $DISPLAY 2> /dev/null`' | xauth -q nmerge - ;; esac set fnord `for arg in ${1+"$@"} ; do echo ":$arg" done \ | sed -ne 's/^:// s/\\\\/\\\\\\\/g s/'\''/'\''\\\\\\'\'\''/g s/^/'\''/ s/$/'\''/ H ${x s/\n/ /g p }'` shift case "$close_stdfds" in t ) exec > /dev/null 2>&1 ;; esac \${1+"\$@"} 9>&- 8>&- 7>&- 6>&- < /dev/null & __EOF__ } } # xon ends here