home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-385-Vol-1of3.iso
/
c
/
condor40.zip
/
CONDOR
/
src
/
condor_kbdd
/
kbdd.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-10-13
|
11KB
|
408 lines
/*
** Copyright 1986, 1987, 1988, 1989 University of Wisconsin
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted,
** provided that the above copyright notice appear in all copies and that
** both that copyright notice and this permission notice appear in
** supporting documentation, and that the name of the University of
** Wisconsin not be used in advertising or publicity pertaining to
** distribution of the software without specific, written prior
** permission. The University of Wisconsin makes no representations about
** the suitability of this software for any purpose. It is provided "as
** is" without express or implied warranty.
**
** THE UNIVERSITY OF WISCONSIN DISCLAIMS ALL WARRANTIES WITH REGARD TO
** THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
** FITNESS. IN NO EVENT SHALL THE UNIVERSITY OF WISCONSIN BE LIABLE FOR
** ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
** WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
** ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
** OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**
** Authors: Allan Bricker and Michael J. Litzkow,
** University of Wisconsin, Computer Sciences Dept.
**
*/
#include <stdio.h>
#include <utmp.h>
#include <X11/Xlib.h>
#include <X11/Xproto.h>
#include <netdb.h>
#include <errno.h>
#include <pwd.h>
#include <signal.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <netinet/in.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <setjmp.h>
#include "except.h"
#include "sched.h"
#include "debug.h"
#define MINUTES 60
int xfd; /* X file descriptor */
Display *dpy = 0; /* display */
int screen; /* default screen */
Window rootwindow; /* default root window */
XEvent event; /* For events received. */
jmp_buf Env;
char XSockName[512];
int ButtonsGrabbed; /* True when we have the mouse buttons grabbed */
static char *_FileName_ = __FILE__; /* Used by EXCEPT (see except.h) */
char *param();
extern int errno;
int UdpSock; /* Send datagrams to the startd */
char ThisHost[512];
char *MyName;
char *Log;
int PollingFrequency;
int Foreground;
int Termlog;
usage( name )
char *name;
{
dprintf( D_ALWAYS, "Usage: %s [-f] [-t]\n", name );
exit( 1 );
}
main( argc, argv)
int argc;
char *argv[];
{
char **ptr;
int idle_secs;
int error_handler(), io_error_handler();
MyName = *argv;
config( MyName, 0 );
init_params();
if( argc > 3 ) {
usage( argv[0] );
}
for( ptr=argv+1; *ptr; ptr++ ) {
if( ptr[0][0] != '-' ) {
usage( argv[0] );
}
switch( ptr[0][1] ) {
case 'f':
Foreground++;
break;
case 't':
Termlog++;
break;
default:
usage( argv[0] );
}
}
/* This is so if we dump core it'll go in the log directory */
if( chdir(Log) < 0 ) {
EXCEPT( "chdir to log directory <%s>", Log );
}
/* Arrange to run in background */
if( !Foreground ) {
if( fork() )
exit( 0 );
}
/* Set up logging */
dprintf_config( "KBDD", 2 );
dprintf( D_ALWAYS, "**************************************************\n" );
dprintf( D_ALWAYS, "*** CONDOR_KBDD STARTING UP ***\n" );
dprintf( D_ALWAYS, "**************************************************\n" );
dprintf( D_ALWAYS, "\n" );
if( gethostname(ThisHost,sizeof ThisHost) < 0 ) {
EXCEPT( "gethostname" );
}
sprintf( XSockName, "%s:0", ThisHost );
UdpSock = udp_connect( ThisHost, START_UDP_PORT );
XSetErrorHandler( error_handler );
XSetIOErrorHandler( io_error_handler );
setjmp( Env );
wait_until_X_active( PollingFrequency );
/* open the display and determine well-known some parameters */
if (!(dpy = XOpenDisplay(XSockName))) {
EXCEPT( "unable to open display '%s'\n", XDisplayName(XSockName));
}
screen = DefaultScreen(dpy);
rootwindow = RootWindow(dpy, screen);
xfd = ConnectionNumber(dpy);
for(;;) {
wait_for_event();
update_startd();
sleep( PollingFrequency );
}
}
XDR xdr, *xdrs, *xdr_Udp_Init();
update_startd()
{
int cmd;
if( !xdrs ) {
xdrs = xdr_Udp_Init( &UdpSock, &xdr );
xdrs->x_op = XDR_ENCODE;
dprintf( D_ALWAYS, "Initialized XDR stream\n" );
}
/* Send the command */
cmd = X_EVENT_NOTIFICATION;
if( !xdr_int(xdrs, &cmd) ) {
xdr_destroy( xdrs );
dprintf( D_ALWAYS, "xdr_int() failed, destroyed XDR stream\n" );
xdrs = (XDR *)0;
return -1;
}
if( !xdrrec_endofrecord(xdrs,TRUE) ) {
xdr_destroy( xdrs );
dprintf(D_ALWAYS,"xdrrec_endofrecord() failed, destroyed XDR stream\n");
xdrs = (XDR *)0;
return -1;
}
dprintf( D_FULLDEBUG, "Sent notification\n" );
}
init_params()
{
char *pval;
char *tmp;
Log = param( "LOG" );
if( Log == NULL ) {
EXCEPT( "No log directory specified in config file\n" );
}
tmp = param( "POLLING_FREQUENCY" );
if( tmp == NULL ) {
PollingFrequency = 30;
} else {
PollingFrequency = atoi( tmp );
}
if( param("KBDD_DEBUG") == NULL ) {
EXCEPT( "KBDD_DEBUG not defined in config file\n" );
}
Foreground = boolean( "KBDD_DEBUG", "Foreground" );
}
wait_for_event()
{
/* Grab key and mouse events */
XGrabKey(dpy, AnyKey, AnyModifier, rootwindow, False,
GrabModeSync, GrabModeSync);
ButtonsGrabbed = TRUE; /* will be set FALSE if error occurs */
XGrabButton(dpy, AnyButton, AnyModifier, rootwindow, False,
ButtonPressMask, GrabModeSync, GrabModeSync, None, None );
/* Block here until we get an event */
XNextEvent(dpy, &event);
/* Ungrab key and mouse, and replay any events we grabbed */
XUngrabKey(dpy, AnyKey, AnyModifier, rootwindow);
if( ButtonsGrabbed ) {
XUngrabButton(dpy, AnyButton, AnyModifier, rootwindow);
XAllowEvents(dpy, ReplayPointer, CurrentTime);
ButtonsGrabbed = FALSE;
}
XAllowEvents(dpy, ReplayKeyboard, CurrentTime);
XFlush(dpy);
}
/*
** If we try to connect to the X server while it is grabbed by the init
** process, (during the time nobody is logged in via the monitor), we
** will time out. X makes this difficult to handle in several ways,
** 1. we're left with an open file descriptor we can't use, but we don't
** know which one, 2. X insists we should exit when we return from the
** error handler, so we have to avoid that with a longjump, 3. if we
** do this enough times, it breaks the server, (probably it also leaves
** a dangling file descriptor or some such). Since connecting to the
** X server while it is grabbed is such a bad thing to do, we try to avoid
** it here. We watch logins in utmp and try to figure out whether any
** are direct from the monitor so the server will not be grabbed. If some
** "xspert" finds this comment obnoxious and wants to suggest a better way,
** my mailing address is "mike@cs.wisc.edu" -- mike.
*/
wait_until_X_active( period )
int period;
{
FILE *fp;
struct utmp utmp;
dprintf( D_ALWAYS, "Waiting for X to become active...\n" );
if( (fp=fopen("/etc/utmp","r")) == NULL ) {
perror( "fopen of utmp" );
exit( 1 );
}
for(;;) {
while( fread( (char *)&utmp, sizeof utmp, 1, fp ) ) {
if( utmp.ut_name[0] == '\0' )
continue;
if( check_X_active(utmp.ut_host,sizeof(utmp.ut_host),XSockName) ) {
(void)fclose( fp );
return;
}
}
sleep( period );
rewind( fp );
}
}
struct utmp ut;
#define UTMP_HOST_LEN sizeof(ut.ut_host)
char Buf[ UTMP_HOST_LEN + 1 ];
check_X_active( ut_host, host_name_len, XSockName )
char *ut_host;
int host_name_len;
char *XSockName;
{
int len;
/* Get a guaranteed null terminated copy of ut_host */
bcopy( ut_host, Buf, UTMP_HOST_LEN );
if( strcmp(":0",Buf) == MATCH ) {
dprintf( D_ALWAYS, "Found X active, utmp.ut_host = \"%s\"\n", Buf );
return TRUE;
}
if( strcmp(":0.0",Buf) == MATCH ) {
dprintf( D_ALWAYS, "Found X active, utmp.ut_host = \"%s\"\n", Buf );
return TRUE;
}
if( strcmp("unix:0",Buf) == MATCH ) {
dprintf( D_ALWAYS, "Found X active, utmp.ut_host = \"%s\"\n", Buf );
return TRUE;
}
if( strcmp("unix:0.0",Buf) == MATCH ) {
dprintf( D_ALWAYS, "Found X active, utmp.ut_host = \"%s\"\n", Buf );
return TRUE;
}
/* allow "<localhostname>:0" or "localhostname:0.0" */
if( strcmp(XSockName,Buf) == MATCH ) {
dprintf( D_ALWAYS, "Found X active, utmp.ut_host = \"%s\"\n", Buf );
return TRUE;
}
return FALSE;
}
/*
** Seems like the normal case is to get two X errors in a row. If we get
** more than that in 2 minute, abort and leave a core so somebody can
** investigate.
*/
#define MIN_ERROR_INTERVAL (10 * MINUTES)
#define X_STARTUP_INTERVAL (2 * MINUTES)
long LastError, SecondLastError;
error_handler( d, event )
Display *d;
XErrorEvent *event;
{
long now;
char error_text[512];
if( event->request_code == X_GrabButton && event->error_code == BadAccess) {
dprintf( D_FULLDEBUG, "Can't grab mouse buttons\n" );
ButtonsGrabbed = FALSE;
return;
}
dprintf( D_ALWAYS, "Got X Error, errno = %d\n", errno );
dprintf( D_ALWAYS, "\ttype = %d\n", event->type );
dprintf( D_ALWAYS, "\tdisplay = 0x%x\n", event->display );
dprintf( D_ALWAYS, "\tserial = %d\n", event->serial );
dprintf( D_ALWAYS, "\terror_code = %d\n", event->error_code );
dprintf( D_ALWAYS, "\trequest_code = %d\n", event->request_code );
dprintf( D_ALWAYS, "\tminor_code = %d\n", event->minor_code );
XGetErrorText( event->display, event->error_code, error_text,
sizeof(error_text) );
dprintf( D_ALWAYS, "\ttext = \"%s\"\n", error_text );
if( close(d->fd) == 0 ) {
dprintf( D_ALWAYS, "Closed display fd (%d)\n", d->fd );
} else {
dprintf( D_ALWAYS, "Can't close display fd (%d)\n", d->fd );
}
(void)time( &now );
if( now - SecondLastError < MIN_ERROR_INTERVAL ) {
abort();
} else {
SecondLastError = LastError;
LastError = now;
longjmp( Env, 1 );
}
}
io_error_handler( d )
Display *d;
{
long now;
dprintf( D_ALWAYS, "Got X I/O Error, errno = %d\n", errno );
if( close(d->fd) == 0 ) {
dprintf( D_ALWAYS, "Closed display fd (%d)\n", d->fd );
} else {
dprintf( D_ALWAYS, "Can't close display fd (%d)\n", d->fd );
}
(void)time( &now );
if( now - SecondLastError < MIN_ERROR_INTERVAL ) {
abort();
} else {
SecondLastError = LastError;
LastError = now;
sleep( X_STARTUP_INTERVAL );
longjmp( Env, 1 );
}
}
SetSyscalls(){}