[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Xsession over ssh -> remdm



I hope this is the right forum for this...

For various reasions I want to run a complete Xsession over ssh the
standard answer as to how to do this is:
 ssh -X user@host /etc/X11/Xsession

or a bit more advanced:
 #setup a MIT magick cookie ( Yes I know this is a bit lame but it works)
 randomkey=$(echo $(( $RANDOM * $RANDOM * 2 )))
 randomkey=${randomkey}${randomkey}
 xauth add $(hostname)/unix:1 . $randomkey
 xauth add $(hostname):1 . $randomkey
 #start an Xdisplay
 Xnest :1 -auth ~/.Xauthority 2>/dev/null &
 XPID=$!
 sleep 2
 #setup DISPLAY
 export DISPLAY=:1
 ssh -X user@host /etc/X11/Xsession
 #When session ends kill the Xserver
 kill $XPID

Even this is unsatisfactory for 2 reasons which xdm or startx or xinit
fix for conventional uses of X.

1) During startup of Xsession the progs xrdb and xsetroot and friends may
make transatory connections to the Xserver. When each connection to the
server closes it is the "last" client to exit so the X server resets.

>From what I can see of the xdm/xinit code a connection is made to the
X server before the Xsession script is started so that the resets do not
occur as  xrdb and xsetroot and friends run.

2) When the logout option of your session windowmanager etc is chosen then
the windowmanager closes down and the Xsession script returns. However
some X clients may still have active connections to the X server which
prevents both the X server from reseting and ssh from returning.

>From what I can see of the xdm/xinit code when the Xsession script returns
xdm/xinit then forcably kills the X server process (using unix facilities
rather than Xlib facilities).

I have come up with a temporary solution and thus the outline of a
propper solution.

The solution is in two parts:

1) start an X client which connects to the X server before the Xsession
script starts (like xdm/xinit)

2) xkill any clients which remain after the Xsession script returns. This
is unlike xdm/xinit which seem to locally kill the X server but as my
Xserver is remote from the Xsession script this can't happen.

This solution I call /usr/bin/ssh-xsession and looks like this:

 #!/bin/bash
 #open connection to display to foil xrdb etc (and display motd)
 /usr/X11R6/bin/xmessage -geometry -0+0 -buttons "" -file /etc/motd &
 #Run the X session
 /etc/X11/Xsession
 #Kill any remaining X clients so that ssh can return
 for id in $(/usr/X11R6/bin/xwininfo -all -root  | grep -e '^     0x'|
 awk  '{print $1}')
 do
         /usr/X11R6/bin/xkill -id $id
 done

The ssh command then calls /usr/bin/ssh-xsession rather than
/etc/X11/Xsession.

This script is a hack. The choice of xmessage to display /etc/motd is
convenient for my site but is not a generic solution.

The grep/awk action to get a list of remaining X clients seems to work for
me but it is not eligant and any X client which decides to ignore xkill
stops ssh from returning which is not clean.

The proper solution is probably to have a C program maybe called remdm for
remote display manager. This should open a minimal connection to the
display, then run Xsession, then close any remaining X clients with
proper error checking to ensure a clean exit.

I am not a c programmer but I have collected together some parts of
xinit.c and xkill.c (from xfree86 distrib)  into the following (which I
don't think compiles). May be this could form the _basis_ of remdm a C
replacement for the ssh-xsession script above.

/**********************************************/
/*

Copyright 1988, 1998  The Open Group

Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

Except as contained in this notice, the name of The Open Group shall
not be used in advertising or otherwise to promote the sale, use or
other dealings in this Software without prior written authorization
from The Open Group.

*/
/*

Compile with:
 gcc -L/usr/X11R6/lib/ -lX11 -lXmuu  sshxinit.c -o sshxinit

*/

#include <X11/Xlib.h>
#include <X11/Xproto.h>
#include <stdio.h>
#include <stdlib.h>

static int kill_all_windows ( Display *dpy, int screenno, Bool top );
static int catch_window_errors ( Display *dpy, XErrorEvent *ev );


char *displayNum;
Display *xd;
Bool top = False;



main()
{
/* Open display as set by environment (hence NULL) */
  xd=XOpenDisplay(NULL);

system ("/etc/X11/Xsession");

 kill_all_windows(xd, DefaultScreen(xd) , top);

}
static int
catch_window_errors(Display *dpy, XErrorEvent *ev)
{
    return 0;
}

static int
kill_all_windows(Display *dpy, int screenno, Bool top)
{
    Window root = RootWindow (dpy, screenno);
    Window dummywindow;
    Window *children;
    unsigned int nchildren;
    unsigned int i;
    XWindowAttributes attr;

    XSync (dpy, 0);
    XSetErrorHandler (catch_window_errors);

    nchildren = 0;
    XQueryTree (dpy, root, &dummywindow, &dummywindow, &children, &nchildren);
    if (!top) {
	for (i = 0; i < nchildren; i++) {
	    if (XGetWindowAttributes(dpy, children[i], &attr) &&
		(attr.map_state == IsViewable))
		children[i] = XmuClientWindow(dpy, children[i]);
	    else
		children[i] = 0;
	}
    }
    for (i = 0; i < nchildren; i++) {
	if (children[i])
	    XKillClient (dpy, children[i]);
    }
    XFree ((char *)children);

    XSync (dpy, 0);
    XSetErrorHandler (NULL);		/* pretty stupid way to do things... */

    return 0;
}

/**********************************************/

--
Alex Owen
owen@cus.org.uk





Reply to: