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 >
C/C++ Source or Header  |  1989-10-13  |  11KB  |  408 lines

  1. /* 
  2. ** Copyright 1986, 1987, 1988, 1989 University of Wisconsin
  3. ** 
  4. ** Permission to use, copy, modify, and distribute this software and its
  5. ** documentation for any purpose and without fee is hereby granted,
  6. ** provided that the above copyright notice appear in all copies and that
  7. ** both that copyright notice and this permission notice appear in
  8. ** supporting documentation, and that the name of the University of
  9. ** Wisconsin not be used in advertising or publicity pertaining to
  10. ** distribution of the software without specific, written prior
  11. ** permission.  The University of Wisconsin makes no representations about
  12. ** the suitability of this software for any purpose.  It is provided "as
  13. ** is" without express or implied warranty.
  14. ** 
  15. ** THE UNIVERSITY OF WISCONSIN DISCLAIMS ALL WARRANTIES WITH REGARD TO
  16. ** THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  17. ** FITNESS. IN NO EVENT SHALL THE UNIVERSITY OF WISCONSIN  BE LIABLE FOR
  18. ** ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  19. ** WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  20. ** ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  21. ** OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22. ** 
  23. ** Authors:  Allan Bricker and Michael J. Litzkow,
  24. **              University of Wisconsin, Computer Sciences Dept.
  25. ** 
  26. */ 
  27.  
  28.  
  29. #include <stdio.h>
  30. #include <utmp.h>
  31. #include <X11/Xlib.h>
  32. #include <X11/Xproto.h>
  33. #include <netdb.h>
  34. #include <errno.h>
  35. #include <pwd.h>
  36. #include <signal.h>
  37. #include <ctype.h>
  38. #include <sys/types.h>
  39. #include <sys/socket.h>
  40. #include <sys/param.h>
  41. #include <sys/file.h>
  42. #include <sys/time.h>
  43. #include <sys/resource.h>
  44. #include <netinet/in.h>
  45. #include <rpc/types.h>
  46. #include <rpc/xdr.h>
  47. #include <setjmp.h>
  48. #include "except.h"
  49. #include "sched.h"
  50. #include "debug.h"
  51.  
  52.  
  53. #define MINUTES 60
  54.  
  55. int xfd;           /* X file descriptor */
  56. Display *dpy = 0;  /* display */
  57. int screen;        /* default screen */
  58. Window rootwindow; /* default root window */
  59. XEvent event;      /* For events received. */
  60. jmp_buf    Env;
  61. char    XSockName[512];
  62. int        ButtonsGrabbed;    /* True when we have the mouse buttons grabbed */
  63.  
  64.  
  65.  
  66. static char *_FileName_ = __FILE__;        /* Used by EXCEPT (see except.h)     */
  67.  
  68. char    *param();
  69.  
  70. extern int    errno;
  71.  
  72. int        UdpSock;    /* Send datagrams to the startd */
  73. char    ThisHost[512];
  74. char    *MyName;
  75.  
  76. char    *Log;
  77. int        PollingFrequency;
  78. int        Foreground;
  79. int        Termlog;
  80.  
  81. usage( name )
  82. char    *name;
  83. {
  84.     dprintf( D_ALWAYS, "Usage: %s [-f] [-t]\n", name );
  85.     exit( 1 );
  86. }
  87.  
  88. main( argc, argv)
  89. int        argc;
  90. char    *argv[];
  91. {
  92.     char    **ptr;
  93.     int        idle_secs;
  94.     int        error_handler(), io_error_handler();
  95.  
  96.     MyName = *argv;
  97.     config( MyName, 0 );
  98.     init_params();
  99.  
  100.     if( argc > 3 ) {
  101.         usage( argv[0] );
  102.     }
  103.     for( ptr=argv+1; *ptr; ptr++ ) {
  104.         if( ptr[0][0] != '-' ) {
  105.             usage( argv[0] );
  106.         }
  107.         switch( ptr[0][1] ) {
  108.             case 'f':
  109.                 Foreground++;
  110.                 break;
  111.             case 't':
  112.                 Termlog++;
  113.                 break;
  114.             default:
  115.                 usage( argv[0] );
  116.         }
  117.     }
  118.  
  119.         /* This is so if we dump core it'll go in the log directory */
  120.     if( chdir(Log) < 0 ) {
  121.         EXCEPT( "chdir to log directory <%s>", Log );
  122.     }
  123.  
  124.         /* Arrange to run in background */
  125.     if( !Foreground ) {
  126.         if( fork() )
  127.             exit( 0 );
  128.     }
  129.  
  130.         /* Set up logging */
  131.     dprintf_config( "KBDD", 2 );
  132.  
  133.     dprintf( D_ALWAYS, "**************************************************\n" );
  134.     dprintf( D_ALWAYS, "***          CONDOR_KBDD STARTING UP           ***\n" );
  135.     dprintf( D_ALWAYS, "**************************************************\n" );
  136.     dprintf( D_ALWAYS, "\n" );
  137.  
  138.     if( gethostname(ThisHost,sizeof ThisHost) < 0 ) {
  139.         EXCEPT( "gethostname" );
  140.     }
  141.  
  142.     sprintf( XSockName, "%s:0", ThisHost );
  143.  
  144.     UdpSock = udp_connect( ThisHost, START_UDP_PORT );
  145.  
  146.  
  147.     XSetErrorHandler( error_handler );
  148.     XSetIOErrorHandler( io_error_handler );
  149.     setjmp( Env );
  150.     wait_until_X_active( PollingFrequency );
  151.  
  152.         /* open the display and determine well-known some parameters */
  153.     if (!(dpy = XOpenDisplay(XSockName))) {
  154.         EXCEPT( "unable to open display '%s'\n", XDisplayName(XSockName));
  155.     }
  156.  
  157.     screen = DefaultScreen(dpy);
  158.     rootwindow = RootWindow(dpy, screen);
  159.     xfd = ConnectionNumber(dpy);
  160.  
  161.     for(;;) {
  162.         wait_for_event();
  163.         update_startd();
  164.         sleep( PollingFrequency );
  165.     }
  166. }
  167.  
  168. XDR        xdr, *xdrs, *xdr_Udp_Init();
  169.  
  170. update_startd()
  171. {
  172.     int        cmd;
  173.  
  174.     if( !xdrs ) {
  175.         xdrs = xdr_Udp_Init( &UdpSock, &xdr );
  176.         xdrs->x_op = XDR_ENCODE;
  177.         dprintf( D_ALWAYS, "Initialized XDR stream\n" );
  178.     }
  179.  
  180.         /* Send the command */
  181.     cmd = X_EVENT_NOTIFICATION;
  182.     if( !xdr_int(xdrs, &cmd) ) {
  183.         xdr_destroy( xdrs );
  184.         dprintf( D_ALWAYS, "xdr_int() failed, destroyed XDR stream\n" );
  185.         xdrs = (XDR *)0;
  186.         return -1;
  187.     }
  188.  
  189.     if( !xdrrec_endofrecord(xdrs,TRUE) ) {
  190.         xdr_destroy( xdrs );
  191.         dprintf(D_ALWAYS,"xdrrec_endofrecord() failed, destroyed XDR stream\n");
  192.         xdrs = (XDR *)0;
  193.         return -1;
  194.     }
  195.  
  196.     dprintf( D_FULLDEBUG, "Sent notification\n" );
  197. }
  198.  
  199. init_params()
  200. {
  201.     char    *pval;
  202.     char    *tmp;
  203.  
  204.     Log = param( "LOG" );
  205.     if( Log == NULL )  {
  206.         EXCEPT( "No log directory specified in config file\n" );
  207.     }
  208.  
  209.     tmp = param( "POLLING_FREQUENCY" );
  210.     if( tmp == NULL ) {
  211.         PollingFrequency = 30;
  212.     } else {
  213.         PollingFrequency = atoi( tmp );
  214.     }
  215.  
  216.     if( param("KBDD_DEBUG") == NULL ) {
  217.         EXCEPT( "KBDD_DEBUG not defined in config file\n" );
  218.     }
  219.     Foreground = boolean( "KBDD_DEBUG", "Foreground" );
  220. }
  221.  
  222. wait_for_event()
  223. {
  224.         /* Grab key and mouse events */
  225.     XGrabKey(dpy, AnyKey, AnyModifier, rootwindow, False,
  226.          GrabModeSync, GrabModeSync);
  227.     ButtonsGrabbed = TRUE;    /* will be set FALSE if error occurs */
  228.     XGrabButton(dpy, AnyButton, AnyModifier, rootwindow, False,
  229.          ButtonPressMask, GrabModeSync, GrabModeSync, None, None );
  230.  
  231.         /* Block here until we get an event */
  232.     XNextEvent(dpy, &event);
  233.  
  234.         /* Ungrab key and mouse, and replay any events we grabbed */
  235.     XUngrabKey(dpy, AnyKey, AnyModifier, rootwindow);
  236.     if( ButtonsGrabbed ) {
  237.         XUngrabButton(dpy, AnyButton, AnyModifier, rootwindow);
  238.         XAllowEvents(dpy, ReplayPointer, CurrentTime);
  239.         ButtonsGrabbed = FALSE;
  240.     }
  241.     XAllowEvents(dpy, ReplayKeyboard, CurrentTime);
  242.     XFlush(dpy);
  243.  
  244. }
  245.  
  246. /*
  247. ** If we try to connect to the X server while it is grabbed by the init
  248. ** process, (during the time nobody is logged in via the monitor), we
  249. ** will time out.  X makes this difficult to handle in several ways,
  250. ** 1. we're left with an open file descriptor we can't use, but we don't
  251. ** know which one, 2. X insists we should exit when we return from the
  252. ** error handler, so we have to avoid that with a longjump, 3. if we
  253. ** do this enough times, it breaks the server, (probably it also leaves
  254. ** a dangling file descriptor or some such).  Since connecting to the
  255. ** X server while it is grabbed is such a bad thing to do, we try to avoid
  256. ** it here.  We watch logins in utmp and try to figure out whether any
  257. ** are direct from the monitor so the server will not be grabbed.  If some
  258. ** "xspert" finds this comment obnoxious and wants to suggest a better way,
  259. ** my mailing address is "mike@cs.wisc.edu" -- mike.
  260. */
  261. wait_until_X_active( period )
  262. int        period;
  263. {
  264.     FILE    *fp;
  265.     struct utmp utmp;
  266.  
  267.     dprintf( D_ALWAYS, "Waiting for X to become active...\n" );
  268.  
  269.     if( (fp=fopen("/etc/utmp","r")) == NULL ) {
  270.         perror( "fopen of utmp" );
  271.         exit( 1 );
  272.     }
  273.  
  274.     for(;;) {
  275.         while( fread( (char *)&utmp, sizeof utmp, 1, fp ) ) {
  276.             if( utmp.ut_name[0] == '\0' )
  277.                 continue;
  278.  
  279.             if( check_X_active(utmp.ut_host,sizeof(utmp.ut_host),XSockName) ) {
  280.                 (void)fclose( fp );
  281.                 return;
  282.             }
  283.         }
  284.         sleep( period );
  285.         rewind( fp );
  286.     }
  287.  
  288. }
  289.  
  290. struct utmp    ut;
  291. #define UTMP_HOST_LEN sizeof(ut.ut_host)
  292. char    Buf[ UTMP_HOST_LEN + 1 ];
  293.  
  294. check_X_active( ut_host, host_name_len, XSockName )
  295. char    *ut_host;
  296. int        host_name_len;
  297. char    *XSockName;
  298. {
  299.     int     len;
  300.  
  301.         /* Get a guaranteed null terminated copy of ut_host */
  302.     bcopy( ut_host, Buf, UTMP_HOST_LEN );
  303.  
  304.     if( strcmp(":0",Buf) == MATCH ) {
  305.         dprintf( D_ALWAYS, "Found X active, utmp.ut_host = \"%s\"\n", Buf );
  306.         return TRUE;
  307.     }
  308.  
  309.     if( strcmp(":0.0",Buf) == MATCH ) {
  310.         dprintf( D_ALWAYS, "Found X active, utmp.ut_host = \"%s\"\n", Buf );
  311.         return TRUE;
  312.     }
  313.  
  314.     if( strcmp("unix:0",Buf) == MATCH ) {
  315.         dprintf( D_ALWAYS, "Found X active, utmp.ut_host = \"%s\"\n", Buf );
  316.         return TRUE;
  317.     }
  318.  
  319.     if( strcmp("unix:0.0",Buf) == MATCH ) {
  320.         dprintf( D_ALWAYS, "Found X active, utmp.ut_host = \"%s\"\n", Buf );
  321.         return TRUE;
  322.     }
  323.  
  324.         /* allow "<localhostname>:0" or "localhostname:0.0" */
  325.     if( strcmp(XSockName,Buf) == MATCH ) {
  326.         dprintf( D_ALWAYS, "Found X active, utmp.ut_host = \"%s\"\n", Buf );
  327.         return TRUE;
  328.     }
  329.  
  330.     return FALSE;
  331. }
  332.  
  333. /*
  334. ** Seems like the normal case is to get two X errors in a row.  If we get
  335. ** more than that in 2 minute, abort and leave a core so somebody can
  336. ** investigate.
  337. */
  338. #define MIN_ERROR_INTERVAL  (10 * MINUTES)
  339. #define X_STARTUP_INTERVAL  (2 * MINUTES)
  340. long    LastError, SecondLastError;
  341.  
  342. error_handler( d, event )
  343. Display        *d;
  344. XErrorEvent    *event;
  345. {
  346.     long    now;
  347.     char    error_text[512];
  348.  
  349.     if( event->request_code == X_GrabButton && event->error_code == BadAccess) {
  350.         dprintf( D_FULLDEBUG, "Can't grab mouse buttons\n" );
  351.         ButtonsGrabbed = FALSE;
  352.         return;
  353.     }
  354.  
  355.     dprintf( D_ALWAYS, "Got X Error, errno = %d\n", errno );
  356.     dprintf( D_ALWAYS, "\ttype = %d\n", event->type );
  357.     dprintf( D_ALWAYS, "\tdisplay = 0x%x\n", event->display );
  358.     dprintf( D_ALWAYS, "\tserial = %d\n", event->serial );
  359.     dprintf( D_ALWAYS, "\terror_code = %d\n", event->error_code );
  360.     dprintf( D_ALWAYS, "\trequest_code = %d\n", event->request_code );
  361.     dprintf( D_ALWAYS, "\tminor_code = %d\n", event->minor_code );
  362.  
  363.     XGetErrorText( event->display, event->error_code, error_text,
  364.                                                         sizeof(error_text) );
  365.     dprintf( D_ALWAYS, "\ttext = \"%s\"\n", error_text );
  366.  
  367.     if( close(d->fd) == 0 ) {
  368.         dprintf( D_ALWAYS, "Closed display fd (%d)\n", d->fd );
  369.     } else {
  370.         dprintf( D_ALWAYS, "Can't close display fd (%d)\n", d->fd );
  371.     }
  372.  
  373.     (void)time( &now );
  374.     if( now - SecondLastError < MIN_ERROR_INTERVAL ) {
  375.         abort();
  376.     } else {
  377.         SecondLastError = LastError;
  378.         LastError = now;
  379.         longjmp( Env, 1 );
  380.     }
  381. }
  382.  
  383. io_error_handler( d )
  384. Display        *d;
  385. {
  386.     long    now;
  387.  
  388.     dprintf( D_ALWAYS, "Got X I/O Error, errno = %d\n", errno );
  389.  
  390.     if( close(d->fd) == 0 ) {
  391.         dprintf( D_ALWAYS, "Closed display fd (%d)\n", d->fd );
  392.     } else {
  393.         dprintf( D_ALWAYS, "Can't close display fd (%d)\n", d->fd );
  394.     }
  395.  
  396.     (void)time( &now );
  397.     if( now - SecondLastError < MIN_ERROR_INTERVAL ) {
  398.         abort();
  399.     } else {
  400.         SecondLastError = LastError;
  401.         LastError = now;
  402.         sleep( X_STARTUP_INTERVAL );
  403.         longjmp( Env, 1 );
  404.     }
  405. }
  406.  
  407. SetSyscalls(){}
  408.