예제 #1
0
/******************************************************************************
 *
 * main
 *
 *****************************************************************************/
int
main (
        int argc,
        char **argv )
{
    char **cmdLine;
    int    success;
    fd_set readfds, exceptfds;
    int    nfound;
    struct timeval timeoutShort, timeoutLong;
    int    junki,i;
    char  *tmpBuffer;
    int    errorBytes;
    int    firstPass, tmpi;
    char  *tmpProgName = NULL;


    setlocale( LC_ALL, "" );

#ifdef _DTEXEC_NLS16
    Dt_nlInit();
#endif /* _DTEXEC_NLS16 */
 
    /*
     * For debugging purposes, a way to pause the process and allow
     * time for a xdb -P debugger attach. If no args, (e.g. libDtSvc is
     * test running the executable), cruise on.
     */
    if (getenv("_DTEXEC_DEBUG") && (argc > 1)) {
	/*
	 * Don't block in a system call, or on libDtSvc's attempts to
	 * just test exec us.
	 */
	SPINBLOCK
    }

    /*
     * Note: dtSvcProcIdG is used like a boolean to control whether
     * we are communicating with libDtSvc using Tooltalk.
     */
    dtSvcProcIdG = (char *) NULL;	/* assume not communicating with TT */
    ttfdG = -1;

    cmdLine = ParseCommandLine (argc, argv);

    /*
     * If a signal goes off *outside* the upcoming select, we'll need to
     * rediscover the signal by letting select() timeout.
     *
     * We might also set a rediscover flag to fake a signal response.
     */
    rediscoverSigCldG = 0;		/* boolean and counter */
    rediscoverUrgentSigG = 0;		/* boolean and counter */

    InitializeSignalHandling ();

    /*
     * Create a pipe for logging of errors for actions without
     * windows.
     */
    errorpipeG[0] = -1;                 /* by default, no stderr redirection */
    errorpipeG[1] = -1;
    if ( requestTypeG == TRANSIENT ) {    /* should be WINDOW_TYPE NO_STDIO  */
	if ( pipe(errorpipeG) == -1 ) {
	    errorpipeG[0] = -1;
	    errorpipeG[1] = -1;
	}
    }

    if (cmdLine) {
	success = ExecuteCommand (cmdLine);
	if (!success) {
	    /*
	     * Act like we were killed - it will result in a
	     * DtACTION_FAILED.
	     */
	    childPidG = -1;
	    rediscoverUrgentSigG = 1;
	}
    }
    else {
	/*
	 * Act like we had a child and it went away - it will result
	 * in a DtACTION_DONE.
	 */
	childPidG = -1;
	rediscoverSigCldG = 1;
    }

   /*
    * Note when we started so we can compare times when we finish.
    */
   (void) gettimeofday (&startTimeG, &zoneG);

    if (dtSvcProcIdG) {
	if ( !InitializeTooltalk() ) {
	    /*
	     * We have no hope of talking to our caller via Tooltalk.
	     */
	    dtSvcProcIdG = (char *) NULL;
	}
    }

    /*
     * Tie in to the default session and start chatting.
     */
    if (dtSvcProcIdG) tt_session_join(tt_default_session());

    /*
     * Finally send caller our current proc id so they can talk back.
     */
    if (dtSvcProcIdG) IdSelfToCallerRequest();

    /*
     * Monitor file descriptors for activity.  If errors occur on a fds,
     * it will be removed from allactivefdsG after handling the error.
     */
    CLEARBITS(allactivefdsG);

    /*
     * Add Tooltalk
     */
    if ( ttfdG != -1 )
	BITSET(allactivefdsG, ttfdG);          /* add Tooltalk */

    /*
     * Add Error Log
     */
    if ( errorpipeG[0] != -1 )
	BITSET(allactivefdsG, errorpipeG[0]);  /* add read side of error pipe */

    /*
     * Set options for rediscovery and not-rediscovery modes of
     * operation. 
     */
    shutdownPhaseG = SDP_DONE_STARTING;	/* triggered with rediscoverSigCldG */
    timeoutShort.tv_sec  = 0;		/* in quick rediscovery mode */
    timeoutShort.tv_usec = SHORT_SELECT_TIMEOUT;
    timeoutLong.tv_sec  = 86400;	/* don't thrash on rediscovery */
    timeoutLong.tv_usec = 0;

    for (;;) {
	COPYBITS(allactivefdsG, readfds);
	COPYBITS(allactivefdsG, exceptfds);

	if (rediscoverSigCldG || rediscoverUrgentSigG) {
	    nfound =select(MAXSOCKS, FD_SET_CAST(&readfds), FD_SET_CAST(NULL),
				FD_SET_CAST(&exceptfds), &timeoutShort);
 	}
	else {
	    nfound =select(MAXSOCKS, FD_SET_CAST(&readfds), FD_SET_CAST(NULL),
				FD_SET_CAST(&exceptfds), &timeoutLong);
	}

	if (nfound == -1) {
	    /*
	     * Handle select() problem.
	     */
	    if (errno == EINTR) {
		/*
		 * A signal happened - let rediscover flags redirect flow
		 * via short select timeouts.
		 */
	    }
	    else if ((errno == EBADF) || (errno == EFAULT)) {
		/*
		 * A connection probably dropped.
		 */
		if (ttfdG != -1) {
		    if ( GETBIT(exceptfds, ttfdG) ) {
			/*
			 * Tooltalk connection has gone bad.
			 *
			 * Judgement call - when the Tooltalk connection goes
			 * bad, let dtexec continue rather than doing an exit.
			 */
			DetachFromTooltalk(NULL);
		    }
		}

		if (errorpipeG[0] != -1) {
		    if ( GETBIT(exceptfds, errorpipeG[0]) ) {
			/*
			 * Error pipe has gone bad.
			 */
			close(errorpipeG[0]);
			BITCLEAR(allactivefdsG, errorpipeG[0]);
			errorpipeG[0] = -1;
		    }
		}
	    }
	    else {
		/*
		 * We have bad paremeters to select()
		 */
	    }
	    /*
	     * So that select() errors cannot dominate, now behave as
	     * though only a timeout had occured.
	     */
	    nfound = 0;
	}

	if (nfound > 0) {
	    /*
	     * Have some input to process.  Figure out who.
	     */
	    if (ttfdG != -1) {
		if ( GETBIT(readfds, ttfdG) ) {
		    /* Clear bit first, since calling input_handler() could */
		    /* have the side-effect of setting ttfdG to -1! */
		    BITCLEAR(readfds, ttfdG);

		    /*
		     * Tooltalk activity.
		     *
		     * Note that the input_handler parameters match
		     * an XtInputHandler() style callback in case Xt is
		     * ever used.
		     */
		    input_handler((char *) NULL, (int *) &junki,
					(unsigned long *) &junki);
		}
	    }

	    if (errorpipeG[0] != -1) {
		if ( GETBIT(readfds, errorpipeG[0]) ) {
		    /*
		     * Stderr activity.
		     *
		     * Read the errorpipe until no more seems available.
		     * Call that good enough and write a time-stamped
		     * block to the errorLog file.
		     */
		    errorBytes = 0;		/* what we have so far */
		    tmpBuffer  = NULL;
		    firstPass = 1;

		    while (1) {
			char buf;
			nfound =select(MAXSOCKS, FD_SET_CAST(&readfds), FD_SET_CAST(NULL),
			     FD_SET_CAST(NULL), &timeoutShort);
			if (nfound > 0) {
			    tmpi = read (errorpipeG[0], &buf, 1);
			} else {
			    tmpi = 0;
			}

			if ( tmpi > 0 ) {
			    /*
			     * Grow buffer to hold entire error stream.
			     */
			    firstPass = 0;
			    if (tmpBuffer == NULL)
				tmpBuffer = (char *) malloc(
						tmpi + 1);
			    else
				tmpBuffer = (char *) realloc( tmpBuffer,
						errorBytes + tmpi + 1);
			    /*
			     * Drain error pipe.
			     */
			    tmpBuffer[errorBytes] = buf;
			    errorBytes += tmpi;
			    tmpBuffer[errorBytes] = '\0';

			    if (errorBytes < 65535) {
				/*
				 * Pause a bit and wait for a continuation of
				 * the error stream if there is more.
				 */
				select(0, FD_SET_CAST(NULL),
					  FD_SET_CAST(NULL),
					  FD_SET_CAST(NULL), &timeoutShort);
			    }
			    else {
				/*
				 * We have enough to do a dump now.
				 */
				break;
			    }
			}
			else {
			    /*
			     * No more to read.
			     */
			    if (firstPass) {
				/*
				 * On the first pass after select(), if we have 0 bytes,
				 * it really means the pipe has gone down.
				 */
				close(errorpipeG[0]);
				BITCLEAR(allactivefdsG, errorpipeG[0]);
				BITCLEAR(readfds, errorpipeG[0]);
				errorpipeG[0] = -1;
			    }
			    break;
			}
		    }

		    if (tmpBuffer) {

			if (!tmpProgName) {
			    tmpProgName = (char *) malloc (strlen (argv[0]) + 
							   strlen (cmdLine[0]) +
							   5);
			    if (!tmpProgName)
				tmpProgName = argv[0];
			    else {
				/*
				 * To identify the process for this stderr,
				 * use both argv[0] and the name of the
				 * process that was execvp'd
				 */
				(void) strcpy (tmpProgName, "(");
			        (void) strcat (tmpProgName, argv[0]);
				(void) strcat (tmpProgName, ") ");
				(void) strcat (tmpProgName, cmdLine[0]);
			    }
			}
			DtMsgLogMessage( tmpProgName, DtMsgLogStderr, "%s", 
					 tmpBuffer );
			free( tmpBuffer );
		    }

		    if (errorpipeG[0] != -1)
			BITCLEAR(readfds, errorpipeG[0]);
		}
	    }
	    /*
	     * So that select() data cannot dominate, now behave as
	     * though only a timeout had occured.
	     */
	    nfound = 0;
	}

	if (nfound == 0) {
	    /*
	     * Timeout.  We are probably rediscovering and have entered
	     * a shutdown phase.   The following rediscover handlers are
	     * in priority order.
	     *
	     * Note that by way of timeouts and events, we will make
	     * multiple passes through this block of code.
	     */

	    if (rediscoverUrgentSigG) {
		/*
		 * Handle urgent signal.
		 *
		 * Tact: wait awhile and see if a SIGCLD will happen.
		 * If it does, then a normal shutdown will suffice.
		 * If a SIGCLD does not happen, then do a raw exit(0).
		 * Exit is required for BBA anyway.
		 */

		if (rediscoverSigCldG)
		    /*
		     * Rather than act on the Urgent Signal, defer to the
		     * SIGCLD Signal shutdown process.
		     */
		    rediscoverUrgentSigG = 0;
		else
		    /*
		     * Still in a mode where we have an outstanding
		     * Urgent Signal but no SIGCLD.  Bump a counter
		     * which moves us closer to doing an exit().
		     */
		    rediscoverUrgentSigG++;

		/*
		 * After 5 seconds (add select timeout too) waiting for
		 * a SIGCLD, give up and exit.
		 */
		if (rediscoverUrgentSigG > ((1000/SHORT_SELECT_TIMEOUT)*5) ) {
#if defined(__aix) || defined (__osf__) || defined(CSRG_BASED) || defined(linux)
		    PanicSignal(0);
#else
		    PanicSignal();
#endif
		}
	    }

	    if (rediscoverSigCldG) {
		/*
		 * Handle SIGCLD signal.
		 *
		 * Under SIGCLD, we will make multiple passes through the
		 * following, implementing a phased shutdown.
		 */
		if (shutdownPhaseG == SDP_DONE_STARTING) {
		    /*
		     * Send Done(Request) for starters.
		     */
		    if (dtSvcProcIdG) DoneRequest(_DtActCHILD_DONE);

		    if (dtSvcProcIdG) {
			/*
			 * Sit and wait for the Done Reply in select()
			 */
			shutdownPhaseG = SDP_DONE_REPLY_WAIT;
		    }
		    else {
			/*
			 * Unable to send Done Reply.  Assume we're on
			 * our own from now on.
			 */
			shutdownPhaseG = SDP_DONE_PANIC_CLEANUP;
		    }
		}

		if (shutdownPhaseG == SDP_DONE_REPLY_WAIT) {
		    /*
		     * After 5 minutes of passing through REPLY_WAIT,
		     * assume the Done(Reply) will never come in and
		     * move on.
		     */
		    rediscoverSigCldG++;
		    if (rediscoverSigCldG > ((1000/SHORT_SELECT_TIMEOUT)*300)) {

			if (dtSvcProcIdG) {
			    /*
			     * Try to detatch from Tooltalk anyway.
			     */
			    DetachFromTooltalk(NULL);
			}

			shutdownPhaseG = SDP_DONE_PANIC_CLEANUP;
		    }

		    /*
		     * See if the Tooltalk connection is still alive.   If
		     * not, then no reason to wait around.
		     */
		    else if (!dtSvcProcIdG) {
			shutdownPhaseG = SDP_DONE_PANIC_CLEANUP;
		    }

		}

		if (shutdownPhaseG == SDP_DONE_REPLIED) {
		    /*
		     * We have our Done(Reply), so proceed.
		     */

		    if (dtSvcProcIdG)
			shutdownPhaseG = SDP_FINAL_LINGER;
		    else
			shutdownPhaseG = SDP_DONE_PANIC_CLEANUP;
		}

		if (shutdownPhaseG == SDP_DONE_PANIC_CLEANUP) {
		    /*
		     * We cannot talk with caller, so do cleanup
		     * of tmp files.
		     */
		    for (i = 0; i < tmpFileCntG; i++ ) {
			chmod( tmpFilesG[i], (S_IRUSR|S_IWUSR) );
			unlink( tmpFilesG[i] );
		    }

		    shutdownPhaseG = SDP_FINAL_LINGER;
		}

		if (shutdownPhaseG == SDP_FINAL_LINGER) {
		    /*
		     * All done.
		     */
		    static int skipFirst = 1;

		    if (skipFirst) {
			/*
			 * Rather than a quick departure from the select()
			 * loop, make one more pass.  If the child has gone
			 * down quickly, the SIGCLD may have caused us to
			 * get here before any errorPipeG information has
			 * had a chance to reach us.
			 */
			skipFirst = 0;
		    }
		    else {
			FinalLinger();
		    }
		}
	    }
	}
    }
}
예제 #2
0
WaitForInput()
{
    int	Quit();
    int i;
    struct timeval waittime, *wt;
    long timeout;
    long readyClients[mskcnt];
    long curclient;
    int selecterr;

    CLEARBITS(readyClients);

    COPYBITS(AllSockets, LastSelectMask);

    wt = NULL;

/* 
    if (!ANYSET(AllClients))
    {
    	wt = &waittime;
	waittime.tv_sec  = 5*60;
	waittime.tv_usec = 0;
    }
    else {
	sleep(1);
        alarm(NSECONDS);
        signal(SIGALRM, catchit);
        while(wait((int *)0) > 0);
    	alarm(0);
    	wt = NULL;
    }

*/
    i = select (MAXSOCKS, LastSelectMask, (int *) NULL, (int *) NULL, wt);

    selecterr = errno;
    
    if (i <= 0) /* An error or timeout occurred */
    {
	if(i == 0)
		Quit();
	if (i < 0) 
		if (selecterr == EBADF)    /* Some client disconnected */
			CheckConnections ();
		else if (selecterr != EINTR)
			fprintf(stderr, "WaitForInput(): select: errno=%d\n",
								selecterr);
    }
    else
    {
	MASKANDSETBITS(readyClients, LastSelectMask, AllClients); 
	if (LastSelectMask[0] & WellKnownConnections) 
		   EstablishNewConnections();
    }
    if (ANYSET(readyClients))
    {
	for (i=0; i<mskcnt; i++)
	{
	    while (readyClients[i])
	    {
		curclient = NextSetBit (readyClients[i]) - 1;
		ServiceClient(curclient);	
		readyClients[i] &= ~(1 << curclient);
	    }
	}	
    }
}