/*
 * nqsd/nqs_reqexi.c
 * 
 * DESCRIPTION:
 *
 *	This module contains the procedure:  nqs_reqexi(), which
 *	is invoked by the shepherd process created in nqs_spawn(),
 *	when a request has ended execution.
 *
 *	Original Author:
 *	-------
 *	Brent A. Kingsbury, Sterling Software Incorporated.
 *	April 14, 1986.
 */

#include <libnqs/license.h>
#include <libnqs/proto.h>
#include <libnqs/nqspacket.h>		/* NQS local message packet types */
#include <libnqs/informcc.h>		/* NQS information completion */
					/* codes and masks */
#include <libnqs/requestcc.h>		/* NQS request completion codes */

#include <libsal/license.h>
#include <libsal/proto.h>
#include <libsal/defines.h>
#include <nqsdaemon/features.h>

#include <stdlib.h>

static void reqcom ( struct request *request, int exitcode );
static void shoreqmsg ( struct rawreq *rawreq, struct requestlog *requestlog, char *text );
static void stopentity ( struct device *device );

/*
 *	#defines local to this module.
 */
#define	VBAT	000001			/* Valid RCM_ for batch queue */
#define	VDEV	000002			/* Valid RCM_ for device queue */
#define	VNET	000004			/* Valid RCM_ for network queue */
#define	VPIP	000010			/* Valid RCM_ for pipe queue */


/*** nqs_reqexi
 *
 *
 *	void nqs_reqexi():
 *
 *	This module contains the procedure:  nqs_reqexi(), which
 *	is invoked by the shepherd process created in nqs_spawn(),
 *	when a request has ended execution.
 */
void nqs_reqexi (
	struct request *request,	/* Request structure for request */
	struct transact *transaction,	/* Transaction for request */
	struct rawreq *rawreq,		/* Ptr to raw request structure */
					/* for request */
	struct requestlog *requestlog,	/* Mail request log record */
	struct device *device)		/* Device used to satisfy request */
					/* (can be NIL for non-device */
					/*  requests) */
{

	static short valid[] = {
		VBAT,				/* RCM_2MANYENVARS */
			VDEV |	VNET |	VPIP,	/* RCM_2MANYSVARGS */
		VBAT |	VDEV,			/* RCM_ABORTED */
		VBAT |	VDEV |	VNET |	VPIP,	/* RCM_BADCDTFIL */
			VDEV |	VNET |	VPIP,	/* RCM_BADSRVARG */
/*
 *	For the current ****TRIAGE**** implementation, pipe queue
 *	servers are permitted to return RCM_DELIVERED, RCM_DELIVEREXP,
 *	RCM_DELIVERFAI, and RCM_DELIVERRETX.
 */
				VNET |	VPIP,	/* RCM_DELIVERED */
				VNET |	VPIP,	/* RCM_DELIVEREXP */
				VNET |	VPIP,	/* RCM_DELIVERFAI */
				VNET |	VPIP,	/* RCM_DELIVERRETX */
			VDEV,			/* RCM_DEVOPEFAI */
		VBAT |	VDEV |	VNET |	VPIP,	/* RCM_ENFILERUN */
		VBAT |	VDEV |	VNET |	VPIP,	/* RCM_ENOSPCRUN */
		0,				/* RCM_EXECUTING */
		VBAT |	VDEV,			/* RCM_EXITED */
		VBAT |	VDEV |	VNET |	VPIP,	/* RCM_INSUFFMEM */
				VNET |	VPIP,	/* RCM_INTERRUPTED */
		VBAT |	VDEV |	VNET |	VPIP,	/* RCM_MIDUNKNOWN */
				VNET,		/* RCM_NETREQDEL */
		VBAT |	VDEV |	VNET |	VPIP,	/* RCM_NOACCAUTH */
		VBAT |	VDEV |	VNET |	VPIP,	/* RCM_NOMOREPROC */
				VNET |	VPIP,	/* RCM_NONSECPORT */
		0,				/* RCM_NORESTART */
			VDEV |	VNET |	VPIP,	/* RCM_NOSVRETCODE */
					VPIP,	/* RCM_PATHLEN */
					VPIP,	/* RCM_PIPREQDEL */
		0,				/* RCM_REBUILDFAI */
					VPIP,	/* RCM_REQCOLLIDE */
				VNET |	VPIP,	/* RCM_RETRYLATER */
					VPIP,	/* RCM_ROUTED */
					VPIP,	/* RCM_ROUTEDLOC */
					VPIP,	/* RCM_ROUTEEXP */
					VPIP,	/* RCM_ROUTEFAI */
					VPIP,	/* RCM_ROUTERETX */
			VDEV |	VNET |	VPIP,	/* RCM_SERBRKPNT */
			VDEV |	VNET |	VPIP,	/* RCM_SEREXEFAI */
				VNET |	VPIP,	/* RCM_SERVESIGERR */
		VBAT,				/* RCM_SHEXEF2BIG */
		VBAT |	VDEV,			/* RCM_SHUTDNABORT */
		VBAT |	VDEV,			/* RCM_SHUTDNREQUE */
		VBAT,				/* RCM_SSHBRKPNT */
		VBAT,				/* RCM_SSHEXEFAI */
				VNET,		/* RCM_STAGEOUT */
				VNET,		/* RCM_STAGEOUTBAK */
				VNET,		/* RCM_STAGEOUTFAI */
		VBAT |	VDEV |	VNET |	VPIP,	/* RCM_UNABLETOEXE */
		VBAT |	VDEV |	VNET |	VPIP,	/* RCM_UNAFAILURE */
		VBAT,				/* RCM_UNCRESTDERR */
		VBAT,				/* RCM_UNCRESTDOUT */
		0,				/* RCM_UNDEFINED */
		VBAT,				/* RCM_USHBRKPNT */
		VBAT,				/* RCM_USHEXEFAI */
				VNET		/* RCM_STAGEOUTLCH */
	};

	static char putin_failed[]  = "Placing request in failed directory.\n";
	static char being_deleted[] = "Request being deleted.\n";
	static char stopallque[]    = "Stopping all queues to conserve remaining resources.\n";


	short reason;		/* Reason bits of completion code */
	short endmail;		/* Send mail on request end flag */
	short endbcst;		/* Send broadcast on request end flag */
	struct nqsqueue *serverq;	/* Queue in which request was running*/


	/*
	 *  Begin:
	 *  ------
	 *  Validate completion code.
	 */
	serverq = request->queue;	/* Server queue */
	reason = (requestlog->svm.rcm & XCI_REASON_MASK);
	if (reason < 0 || reason > (RCM_MAXRCM & XCI_REASON_MASK) ||
	   (requestlog->svm.rcm & XCI_TRANSA_MASK)) {
		/*
		 *  The request completion code is invalid.
		 */
		reason = (RCM_UNDEFINED & XCI_REASON_MASK);
		requestlog->svm.rcm = RCM_UNDEFINED;
	}
	endmail = (rawreq->flags & RQF_ENDMAIL);
	endbcst = (rawreq->flags & RQF_ENDBCST);
	switch (serverq->q.type) {
	case QUE_BATCH:
		if (!(valid [reason] & VBAT)) {
			requestlog->svm.rcm = RCM_UNDEFINED;
		}
		if (endbcst) nqs_broadcast (rawreq, requestlog, MSX_ENDED);
		if (!endmail) {
			/*
			 *  See if there are any other reasons for why we
			 *  should send mail concerning the request.
			 */
			if (!requestlog->reqrcmknown) {
				/*
				 *  A system crash has destroyed our knowledge
				 *  of the batch request completion status, so
				 *  we send mail to the user to confess our
				 *  bumbling incompetence.
				 */
				endmail = 1;
			}
			else {
				/*
				 *  At the very least, the request completion
				 *  code is known.
				 *
				 *  Determine if any output file disposition
				 *  deserves comment.
				 */
				endmail = mai_outfiles (rawreq, requestlog);
			}
		}

#if             ADD_TAMU | ADD_NQS_TMPDIR
	  	nqs_RemoveTmpdir(rawreq);
#endif
#if		ADD_NQS_SCRIPTS
	  	nqs_RunEpilogueScript(serverq->q.namev.name);
#endif
                /* OK, lets log the job exit. This didn't use to be standard */
                sal_dprintf(SAL_DEBUG_INFO, SAL_DEBUG_MSG_DEBUGHIGH, "nqs_reqser(): exit %d.%s in %s\n",
                        rawreq->orig_seqno,
                        rawreq->quename,
                        nmap_get_nam (rawreq->orig_mid));
		break;
	case QUE_DEVICE:
		if (!(valid [reason] & VDEV)) {
			requestlog->svm.rcm = RCM_UNDEFINED;
		}
		break;
	case QUE_NET:
		if (!(valid [reason] & VNET)) {
			requestlog->svm.rcm = RCM_UNDEFINED;
		}
		break;
	case QUE_PIPE:
		if (!(valid [reason] & VPIP)) {
			requestlog->svm.rcm = RCM_UNDEFINED;
		}
		break;
	}
	/*
	 *  Adjust request transaction state (if necessary).
	 */
	if (transaction->state == RTS_EXECUTING &&
	   !(request->status & RQF_WASEXE)) {
		/*
		 *  If the request was not restarting, then there are
		 *  certain conditions under which we must restore the
		 *  transaction state of the request to RTS_STASIS.
		 */
		switch (requestlog->svm.rcm) {
		case RCM_2MANYSVARGS:
		case RCM_BADSRVARG:
		case RCM_DEVOPEFAI:
		case RCM_ENFILERUN:
		case RCM_ENOSPCRUN:
		case RCM_INSUFFMEM:
		case RCM_INTERRUPTED:
		case RCM_NOMOREPROC:
		case RCM_NONSECPORT:
		case RCM_RETRYLATER:
		case RCM_SERBRKPNT:
		case RCM_SEREXEFAI:
		case RCM_SERVESIGERR:
		case RCM_SSHEXEFAI:
			/*
			 *  For every request completion code that indicates
			 *  a requeueable condition that is NOT identical to
			 *  RCM_SHUTDNREQUE (in which case the transaction
			 *  state should be left alone), we must return the
			 *  transaction state to RTS_STASIS.
			 */
			transaction->state = RTS_STASIS;
			if (tra_setstate (request->v1.req.trans_id,
					  transaction) == -1) {
				/*
				 *  An error occurred modifying the request
				 *  transaction state.
				 */
				sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "Error setting transaction state in nqs_reqexi().\nErrno: %s.\nTransaction-id: %1d.\n", asciierrno(), request->v1.req.trans_id);
			}
			break;
		}
	}
	switch (requestlog->svm.rcm & XCI_FULREA_MASK) {
	case RCM_2MANYENVARS:
		mai_send (rawreq, requestlog, MSX_DELETED);
		reqcom (request, 000);	/* Delete request */
					/* exit (000) */
	case RCM_2MANYSVARGS:
		sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "Too many server arguments");
		stopentity (device);	/* Requeue request and stop device */
					/* or queue as appropriate */
	case RCM_ABORTED:
		if (endmail) mai_send (rawreq, requestlog, MSX_ABORTED);
		reqcom (request, 000);	/* Delete the request */
	case RCM_BADCDTFIL:
		shoreqmsg (rawreq, requestlog, "E$RCM_BADCDTFIL");
		printf (putin_failed);
		reqcom (request, 001);	/* Place request in failed directory */
					/* exit (001) */
	case RCM_BADSRVARG:
		sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "Bad argument to server");
		stopentity (device);	/* Requeue request and stop device */
					/* or queue as appropriate */
	case RCM_DELIVERED:
		if (rawreq->flags & RQF_TRANSMAIL) {
			mai_send (rawreq, requestlog, MSX_DELIVERED);
		}
		reqcom (request, 000);	/* Delete the request from this */
					/* machine */
	case RCM_DELIVEREXP:
	case RCM_DELIVERFAI:
	case RCM_DELIVERRETX:
		mai_send (rawreq, requestlog, MSX_DELETED);
		reqcom (request, 000);	/* Delete the request from this */
					/* machine */
	case RCM_DEVOPEFAI:
		sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "Device: %s has failed.\n", device->name);
		reqcom (request, 012);	/* Requeue request and stop device */
					/* exit (012) */
	case RCM_ENFILERUN:
		sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "Insufficient number of free file descriptors to spawn request.\n%s", stopallque);
		reqcom (request, 042);	/* Requeue request and stop all */
					/* queues; exit (042) */
	case RCM_ENOSPCRUN:
		sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "Insufficient file system resources to spawn request.\n%s", stopallque);
		reqcom (request, 042);	/* Requeue request and stop all */
					/* queues; exit (042) */
	case RCM_EXITED:
		if (endmail) mai_send (rawreq, requestlog, MSX_ENDED);
		reqcom (request, 000);	/* Delete request */
					/* exit (000) */
	case RCM_INSUFFMEM:
		sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "Insufficient memory to spawn request.\n");
		reqcom (request, 042);	/* Requeue request and stop all */
					/* queues; exit (042) */
	case RCM_INTERRUPTED:
		reqcom (request, 002);	/* Requeue request */
	case RCM_MIDUNKNOWN:
		shoreqmsg (rawreq, requestlog, "RCM_MIDUNKNOWN");
		sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, being_deleted);
		/*
		 *  We cannot send mail to the user since the originating
		 *  machine is no longer known to us!
		 */
		reqcom (request, 000);	/* Delete request */
					/* exit (000) */
	case RCM_NETREQDEL:
		mai_send (rawreq, requestlog, MSX_DELETED);
		reqcom (request, 000);	/* Delete request */
					/* exit (000) */
	case RCM_NOACCAUTH:
		shoreqmsg (rawreq, requestlog, "RCM_NOACCAUTH");
		sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "%sRequest original user-id was: %1d.\n",being_deleted, request->v1.req.uid);
		mai_send (rawreq, requestlog, MSX_DELETED);
		reqcom (request, 000);	/* Delete request */
					/* exit (000) */
	case RCM_NOMOREPROC:
		sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "Insufficient number of processes to run request.\n%s", stopallque);
		reqcom (request, 042);	/* Requeue request and stop all */
					/* queues; exit (042) */
	case RCM_NONSECPORT:
		sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "Server bound to non-secure port");
		stopentity (device);	/* Requeue request and stop device */
					/* or queue as appropriate */
	case RCM_NOSVRETCODE:
		if (serverq->q.type == QUE_DEVICE) {
			sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "No completion code returned for device: %s.\n%s", device->name, putin_failed);
			mai_send (rawreq, requestlog, MSX_FAILED);
			reqcom (request, 011);
					/* Place request in failed directory */
					/* and stop device */
					/* exit (011) */
		}
		if (serverq->q.type == QUE_NET) {
			sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "No completion code returned for network\nE$queue: %s.\n%s",
				fmtmidname(serverq->q.namev.to_destination), putin_failed);
		}
		else 
	    		sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "No completion code returned for queue: %s.\n%s", serverq->q.namev.name, putin_failed);
		mai_send (rawreq, requestlog, MSX_FAILED);
		reqcom (request, 021);	/* Place request in failed directory */
					/* and stop queue */
					/* exit (021) */
	case RCM_PATHLEN:
		mai_send (rawreq, requestlog, MSX_DELETED);
		reqcom (request, 000);	/* Delete request */
					/* exit (000) */
	case RCM_PIPREQDEL:
		reqcom (request, 000);	/* Delete request */
					/* exit (000) */
	case RCM_REQCOLLIDE:
		mai_send (rawreq, requestlog, MSX_DELETED);
		reqcom (request, 000);	/* Delete request */
					/* exit (000) */
	case RCM_RETRYLATER:
 		reqcom (request, 002);	/* Requeue request for retry */
					/* exit (002) */
	case RCM_ROUTED:
		/*
		 *  In this ****TRIAGE**** implementation, RCM_ROUTED
		 *  is equivalent to RCM_DELIVERED.
		 */
		if (rawreq->flags & RQF_TRANSMAIL) {
			mai_send (rawreq, requestlog, MSX_DELIVERED);
		}
		reqcom (request, 000);	/* Delete the request from this */
					/* machine */
	case RCM_ROUTEDLOC:
		if (rawreq->flags & RQF_TRANSMAIL) {
			mai_send (rawreq, requestlog, MSX_DELIVERED);
		}
		reqcom (request, 003);	/* Release request from arriving set */
	case RCM_ROUTEEXP:
	case RCM_ROUTEFAI:
	case RCM_ROUTERETX:
		/*
		 *  In this ****TRIAGE**** implementation, these codes
		 *  are analogous to the DELIVER codes.
		 */
		mai_send (rawreq, requestlog, MSX_DELETED);
		reqcom (request, 000);	/* Delete the request from this */
					/* machine */
	case RCM_SERBRKPNT:
		sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "Server breakpoint reached");
		stopentity (device);	/* Requeue request and stop device */
					/* or queue as appropriate */
	case RCM_SEREXEFAI:
		sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "Server execve() failed");
		stopentity (device);	/* Requeue request and stop device */
					/* or queue as appropriate */
	case RCM_SERVESIGERR:
		sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "Server killed by unforseen signal");
		stopentity (device);	/* Requeue request and stop device */
					/* or queue as appropriate */
	case RCM_SHEXEF2BIG:
		mai_send (rawreq, requestlog, MSX_DELETED);
		reqcom (request, 000);	/* Delete request */
					/* exit (000) */
	case RCM_SHUTDNABORT:
		/*
		 *  Server terminated by receipt of signal that resulted
		 *  from an NQS shutdown SIGTERM/SIGKILL sequence, AND
		 *  the request is NOT restartable.
		 *
		 *  The serious student will note that we have an ambiguous
		 *  situation here.  NQS cannot know when shutting down, if
		 *  the signal death of a request was caused because of the
		 *  NQS SIGTERM/SIGKILL shutdown signal sequence, or because
		 *  a user decided to signal their request when NQS was also
		 *  SIMULTANEOUSLY shutting down.  Thus, this code is not
		 *  perfect.
		 *
		 *  Sigh.
		 */
		mai_send (rawreq, requestlog, MSX_ABORTSHUTDN);
		reqcom (request, 000);	/* Delete request */
					/* exit (000) */
	case RCM_SHUTDNREQUE:
		/*
		 *  Server terminated by receipt of signal that resulted
		 *  from an NQS shutdown SIGTERM/SIGKILL sequence, AND
		 *  the request is restartable.
		 *
		 *  The serious student will note that we have an ambiguous
		 *  situation here.  NQS cannot know when shutting down, if
		 *  the signal death of a request was caused because of the
		 *  NQS SIGTERM/SIGKILL shutdown signal sequence, or because
		 *  a user decided to signal their request when NQS was also
		 *  SIMULTANEOUSLY shutting down.  Thus, this code is not
		 *  perfect.
		 *
		 *  Sigh.
		 */
		reqcom (request, 004);	/* Requeue request killed by signal */
					/* exit (004) */
	case RCM_SSHBRKPNT:
		shoreqmsg (rawreq, requestlog,
			   "Shell breakpoint encountered");
		mai_send (rawreq, requestlog, MSX_DELETED);
		reqcom (request, 020);	/* Delete request; stop queue */
					/* exit (020) */
	case RCM_SSHEXEFAI:
		sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "Shell execve() failed for batch queue: %s.\n%s.\n", serverq->q.namev.name, requestlog->svm.mssg);
		mai_send (rawreq, requestlog, MSX_REQUEUED);
		reqcom (request, 022);	/* Requeue request; stop queue */
					/* exit (022) */
	case RCM_STAGEOUT:
		/* MOREHERE later */
		reqcom (request, 000);	/* Delete request */
					/* exit (000) */
	case RCM_STAGEOUTBAK:
		/* MOREHERE later */
		mai_send (rawreq, requestlog, MSX_ENDED);
		reqcom (request, 000);	/* Delete request */
					/* exit (000) */
	case RCM_STAGEOUTFAI:
		/* MOREHERE later */
		mai_send (rawreq, requestlog, MSX_ENDED);
		reqcom (request, 000);	/* Delete request */
					/* exit (000) */
	case RCM_UNABLETOEXE:
		mai_send (rawreq, requestlog, MSX_DELETED);
		reqcom (request, 000);	/* Delete request */
					/* exit (000) */
	case RCM_UNAFAILURE:
		shoreqmsg (rawreq, requestlog,
			   "Server reports RCM_UNAFAILURE");
		printf (putin_failed);
		mai_send (rawreq, requestlog, MSX_FAILED);
		reqcom (request, 001);	/* Place request in failed directory */
					/* exit (001) */
	case RCM_UNCRESTDERR:
		mai_send (rawreq, requestlog, MSX_ENDED);
		reqcom (request, 000);	/* Delete request */
					/* exit (000) */
	case RCM_UNCRESTDOUT:
		mai_send (rawreq, requestlog, MSX_ENDED);
		reqcom (request, 000);	/* Delete request */
					/* exit (000) */
	case RCM_UNDEFINED:
		/*
		 *  Invalid completion code reported.
		 */
		shoreqmsg (rawreq, requestlog, "Invalid completion code");
	        sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "Received code was %x\n", requestlog->svm.rcm & XCI_FULREA_MASK);
		sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "Completion code text follows:\n");
		analyzercm (requestlog->svm.rcm, SAL_DEBUG_MSG_WARNING, "");
		sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, putin_failed);
		requestlog->svm.rcm = RCM_UNDEFINED;
		requestlog->svm.mssg [0] = '\0';
		mai_send (rawreq, requestlog, MSX_FAILED);
		if (serverq->q.type == QUE_DEVICE) {
			reqcom (request, 011);
					/* Place request in failed */
		}			/* directory and stop dev  */
		reqcom (request, 021);	/* Place request in failed */
	case RCM_USHBRKPNT:
		mai_send (rawreq, requestlog, MSX_DELETED);
		reqcom (request, 000);	/* Delete request */
					/* exit (000) */
	case RCM_USHEXEFAI:
		mai_send (rawreq, requestlog, MSX_DELETED);
		reqcom (request, 000);	/* Delete request */
					/* exit (000) */
	case RCM_STAGEOUTLCH:
		/* MOREHERE later */
		mai_send (rawreq, requestlog, MSX_ENDED);
		reqcom (request, 000);	/* Delete request */
					/* exit (000) */
	}
}


/*** reqcom
 *
 *
 *	void reqcom():
 *	Send a request-complete message to the NQS daemon, and exit().
 */
static void reqcom (struct request *request, int exitcode)
{
#if	IS_POSIX_1 | IS_SYSVr4
	struct tms tms;			/* Process and child execution times */

	fflush (stdout);		/* Force writing of any log */
	fflush (stderr);		/* Messages */
	interclear();
	times (&tms);			/* Get process and child times */
	/*
	 *  Since it is known absolutely that this message is not going
	 *  across an inter-machine boundary, we send the structure
	 *  directly.
	 */
	interwbytes ((char *) &tms, sizeof (struct tms));
#else
#if	IS_BSD
	struct rusage rusage_self;	/* Process resource consumption */
	struct rusage rusage_children;	/* for self and children */

	interclear();
	getrusage (RUSAGE_CHILDREN, &rusage_children);
	getrusage (RUSAGE_SELF, &rusage_self);
	rusage_self.ru_utime.tv_usec += rusage_children.ru_utime.tv_usec;
	if (rusage_self.ru_utime.tv_usec > 1000000) {
		rusage_self.ru_utime.tv_usec -= 1000000;
		rusage_self.ru_utime.tv_sec += 1;
	}
	rusage_self.ru_utime.tv_sec += rusage_children.ru_utime.tv_sec;
	rusage_self.ru_stime.tv_usec += rusage_children.ru_stime.tv_usec;
	if (rusage_self.ru_stime.tv_usec > 1000000) {
		rusage_self.ru_stime.tv_usec -= 1000000;
		rusage_self.ru_stime.tv_sec += 1;
	}
	rusage_self.ru_stime.tv_sec += rusage_children.ru_stime.tv_sec;
	rusage_self.ru_maxrss += rusage_children.ru_maxrss;
	rusage_self.ru_ixrss += rusage_children.ru_ixrss;
	rusage_self.ru_idrss += rusage_children.ru_idrss;
	rusage_self.ru_isrss += rusage_children.ru_isrss;
	rusage_self.ru_minflt += rusage_children.ru_minflt;
	rusage_self.ru_majflt += rusage_children.ru_majflt;
	rusage_self.ru_nswap += rusage_children.ru_nswap;
	rusage_self.ru_inblock += rusage_children.ru_inblock;
	rusage_self.ru_oublock += rusage_children.ru_oublock;
	rusage_self.ru_msgsnd += rusage_children.ru_msgsnd;
	rusage_self.ru_msgrcv += rusage_children.ru_msgrcv;
	rusage_self.ru_nsignals += rusage_children.ru_nsignals;
	rusage_self.ru_nvcsw += rusage_children.ru_nvcsw;
	rusage_self.ru_nivcsw += rusage_children.ru_nivcsw;
	/*
	 *  Since it is known absolutely that this message is not going
	 *  across an inter-machine boundary, we send the structure
	 *  directly.
	 */
	interwbytes ((char *) &rusage_self, sizeof (struct rusage));
#else
BAD SYSTEM TYPE
#endif
#endif
	interw32i (request->v1.req.orig_seqno);	/* Request sequence# */
	interw32u (request->v1.req.orig_mid);	/* Request mid */
	interw32i (exitcode);		/* Disposition code */
	interwstr (request->queue->q.namev.name);
					/* Containing queue name */
	inter (PKT_REQCOM);		/* Send completion notification */
	exit (exitcode);		/* Exit with code to daemon */
}


/*** shoreqmsg
 *
 *
 *	void shoreqmsg():
 *	Show request message displaying request-id.
 */
static void shoreqmsg (
	struct rawreq *rawreq,		/* Raw request struct for request */
	struct requestlog *requestlog,	/* Mail request log record */
	char *text)			/* Text */
{
	sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "%s for request %1ld.%s.\n", text, (long) rawreq->orig_seqno,
		fmtmidname (rawreq->orig_mid));
	if (requestlog->svm.mssg [0] != '\0') {
		sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_INFO, "%s\n", requestlog->svm.mssg);
	}
}


/*** stopentity
 *
 *
 *	void stopentity():
 *	Requeue request and stop device or queue as appropriate.
 */
static void stopentity (struct device *device)
{
	struct request *request;	/* Current request */
	struct nqsqueue *serverq;		/* Server queue */

	if (device ==  NULL) {
	        sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "stopentity for NULL device\n");
		return;
	}
	request = device->curreq;	/* Current request */
	serverq = request->queue;	/* Server queue */
	if (serverq->q.type == QUE_DEVICE) {
		sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "for device: %s.\n", device->name);
		reqcom (request, 012);	/* Requeue request and stop device */
					/* exit (012) */
	}
	if (serverq->q.type == QUE_NET) {
		sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "for network queue: %s.\n",
			fmtmidname (serverq->q.namev.to_destination));
	}
	else 
    		sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "for queue: %s.\n", serverq->q.namev.name);
	reqcom (request, 022);		/* Requeue request and stop queue */
}					/* exit (022) */
