/*
/*	TITLE:                  SYSTEM - ISSUE COMMAND TO SYSTEM ROUTINE
/*	SYSTEM:			COMMON DEC
/*	ENTRY POINT:		SYSTEM
/*	SOURCE FILE:		SYSTEM.C
/*	PROGRAMMER:		Wayne E. Baisley
/*	SOFTWARE TREE:		CCLIB.STS
/*	DATE:			April 3, 1984
/*
/*	REVISIONS      DATE	  PROGRAMMER		DESCRIPTION
/*	---------    --------	--------------	-----------------------------
/*
/*	   0)	     04/03/84	W. E. Baisley	Original release.
/*
/*	   1)	     04/10/84	W. E. Baisley	Add special handling for the 
/*						case where the input device
/*						for a detached process is a
/*						mailbox (e.g. when using MMS).
/*
/*	   2)	     04/13/84	W. E. Baisley	Correct problems which prevented
/*						reuse of this routine.
/*
/*	   3)	     07/30/84	W. E. Baisley	Correct the assignments of SYS$INPUT
/*						and SYS$OUTPUT for the LIB$SPAWN call.
/*
/*	   4)	     09/09/85	W. E. Baisley	Extensively rewritten, to reuse the 
/*						subprocess and mailboxes whenever 
/*						the image calls this routine more than 
/*						once (as does PCC, its most frequent 
/*						caller).
/*
/*	   5)	     09/20/85	W. E. Baisley	Modified to use the new formatting feature 
/*						of the complain routine, and to include the 
/*						calling image's filename in the initial
/*						message.
/*
/*	   6)	     09/20/85	W. E. Baisley	Make the exit_handler delete the process by 
/*						its name, and complain if it can't do it.
/*						Make all the global variables and buffers 
/*						static.  Make system quit trying if it gets 
/*						anything but SS$_NORMAL or SS$_NONEXPR from 
/*						the subprocess SYS$GETJPIW call.
/*
/*	   7)	     09/24/85	W. E. Baisley	Ignore zero-length buffers and those that 
/*						don't start with a number in interpret_status 
/*						to correct a synchronization problem that 
/*						caused the status report number to be displayed 
/*						at SYS$OUTPUT (and probably a zero return status).
/*
/*	   8)	     09/24/85	W. E. Baisley	Detect when a subprocess exits unexpectedly and 
/*						issue a warning message, flush the mailboxes, 
/*						reset the sub_exit_status, and recreate the 
/*						subprocess.  Change the modus operandi for the 
/*						complaint sections so that we don't append any 
/*						messages to previous messages.  Add a (possibly 
/*						redundant) complaint if the LIB$SPAWN fails.
/*						Move the mailbox descriptors so they can be 
/*						reused if the subprocess is to be recreated.
/*						Don't bother deassigning mailboxes in exit_handler 
/*						since they'll go away on their own anyway.
/*
/*	   9)	     09/25/85	W. E. Baisley	Make issue_command clear the read attention AST 
/*						if we're flushing (which only happens on a 
/*						subprocess recreate), and make queue_read_attn_ast 
/*						indicate whether a set or a clear failed.
/*
/*	   10)	     10/09/85	W. E. Baisley	Make system_exit_desc static so that system can 
/*						be included in a shared region.
/*
/*	   11)	     10/30/85	W. E. Baisley	Use the new cimageid routine to get our image name.
/*						Use the getpid routine to get our Process ID.
/*
/*	NOTES:
/*
/*		This routine operates in the following fashion:
/*
/*		1)  On the first pass (whenever the global variable "first_pass" is set, a 
/*		    cooperating subprocess is initialized as described in steps 2 through 6.
/*
/*		2)  A temporary mailbox is created and used for the SYS$INPUT assignment for the
/*		    subprocess.  This mailbox is named 
/*
/*				"image_processid_INPUT", where 
/*
/*		    "image"     is the first 9 or fewer alphanumeric characters of the calling image, and
/*		    "processid" is the lower half of the caller's Process ID, in hexadecimal.  
/*
/*		    For example, a call to this routine from an image named "PCC" executing from 
/*		    Process ID 00000008 would produce a mailbox with a name of 
/*
/*				"PCC_0008_INPUT".
/*
/*		3)  A temporary mailbox is created and used for the SYS$OUTPUT assignment for the
/*		    subprocess.  This mailbox is named in a manner similar to the SYS$INPUT mailbox.  
/*		    For example, a call to this routine from an image named "PCC" executing from 
/*		    Process ID 00000008 would produce a mailbox with a name of 
/*
/*				"PCC_0008_OUTPUT".
/*
/*		    Any output which appears in this mailbox as a result of the commands written to 
/*		    the input mailbox (error and informational messages, typically) is copied
/*		    to the caller's SYS$OUTPUT device, via calls to "puts".  The assignment of 
/*		    stdout should probably be left alone because of this, so that operation with
/*		    command procedures and MMS is not impaired.
/*
/*		4)  A cooperating subprocess is spawned by this routine via the LIB$SPAWN service.  
/*		    The subprocess is given a name based on the caller's image name and Process ID, 
/*		    as in the cases of the mailboxes.  The format is 
/*
/*				"image_processid", where 
/*
/*		    "image"     is the first 9 or fewer alphanumeric characters of the calling image, and
/*		    "processid" is the lower half of the caller's Process ID, in hexadecimal.  
/*
/*		    For example, a call to this routine from an image named "PCC" executing from 
/*		    Process ID 00000008 would spawn a subprocess with a name of 
/*
/*				"PCC_0008".
/*
/*		5)  Some initialization commands are issued to the subprocess, to ensure that it 
/*		    behaves as desired.  These commands are :
/*
/*				$ SET NOON
/*				$ SET NOVERIFY
/*
/*		6)  Any errors encountered in these preliminary steps cause this routine to 
/*		    discontinue processing, print an error message on the SYS$OUTPUT device, 
/*		    and return the severity part of the status code.  This routine will attempt 
/*		    to discard the temporary mailboxes as appropriate.  It may happen that 
/*		    the mailboxes and/or the subprocess already exist, due to previous abnormal 
/*		    execution of the calling image (which mysteriously managed to exit without 
/*		    calling our exit handler).  In such a case, the vestigial subprocess is 
/*		    eliminated, which usually causes the mailboxes to disappear as well.  This 
/*		    step is taken prior to the creation of the mailboxes and subprocess, and 
/*		    therefore takes place "transparently".
/*
/*		7)  Continuing the first pass, and on all secondary calls to this routine, the 
/*		    given command line is prefixed with the DCL command string token "$ ", and 
/*		    written to the subprocess' SYS$INPUT mailbox, which causes the execution of 
/*		    the command.  Whenever DCL (or other CLI) requests the next command, a
/*		    "REPORT_STATUS" command is issued to the subprocess to obtain the given 
/*		    command line's completion status.  The output from the "REPORT_STATUS" 
/*		    command is not echoed to the caller's SYS$OUTPUT.  The severity part of 
/*		    completion status is returned to the caller.  The "REPORT_STATUS" command 
/*		    is the DCL command 
/*
/*				$ WRITE SYS$OUTPUT "''F$INTEGER ($STATUS)'"
/*
/*		8)  The restrictions indicated for the LIB$SPAWN routine apply to this routine.
/*		    Among other things, this means that this routine cannot be called by a 
/*		    task running directly as a detached process or subprocess (i. e., without
/*		    a CLI), nor if the default CLI is not DCL.  Refer to Section 2.102 of the 
/*		    VAX-11 Run-Time Library Reference Manual for more complete information.
/*
/*		9)  When the calling image exits, this routine will attempt to delete the 
/*		    subprocess and undo the assignments to the mailboxes, by means of a declared 
/*		    exit handler.
/* */
	
#include <ctype.h>
#include <clidef.h>
#include <descrip.h>
#include <dvidef.h>
#include <iodef.h>
#include <iostr.h>
#include <jpidef.h>
#include <prcdef.h>
#include <psldef.h>
#include <ssdef.h>
#include <stsdef.h>
#include <stdio.h>

#define BUFFER_LEN	(132)		/* Message buffer length */
#define	COMMAND_LEN	(132)		/* Command line length */
#define	ERROR_LEN	(192)		/* Complaint buffer length */
#define	IMAGE_QUAL_LEN	(9)		/* Image qualifier length */
#define	MBX_PFX_LEN	(PROCESS_LEN+1)	/* Mailbox base length */
#define	MAILBOX_LEN	(MBX_PFX_LEN+6)	/* Mailbox name length */
#define	PID_QUAL_LEN	(5)		/* PID qualifier length */
#define	PROCESS_LEN	(IMAGE_QUAL_LEN+PID_QUAL_LEN)		/* Process name length */
#define FLAG		(1)		/* Event Flag Number for various wait operations */

#define flush_mbx(mbx_channel) issue_command (NULL, NULL, mbx_channel, mbx_channel, NULL, NULL)

static long first_pass = YES;
static long input_mbx_chan = 0;
static long output_mbx_chan = 0;
static long my_pid = 0;
static long sub_pid = 0;
static long sub_exit_status = 0;
static long final_status = 0;

static int exit_handler ();
static int end_file ();
static int echo_output ();
static int sub_exit ();
static int interpret_status ();

/*		Buffers And Associated String Descriptors		*/

static char my_image [L_cimageid];		/* Image name buffer */
static char error_buf [ERROR_LEN] = "%";	/* Complaint buffer */
static char *end_error_buf = &error_buf [1];	/* End of text in complaint buffer */
static char process_name [PROCESS_LEN + 1];	/* Process name buffer */
static struct dsc$descriptor_s proc_desc = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, process_name };
static char input_mbx_string [MAILBOX_LEN + 1];
static $DESCRIPTOR (input_mbx_desc, input_mbx_string);
static char output_mbx_string [MAILBOX_LEN + 1];
static $DESCRIPTOR (output_mbx_desc, output_mbx_string);

/*		Declare Exit Handler Descriptor		*/

static struct desblk {
	struct desblk *link;		/* Pointer to next descriptor */
	int (*handler) ();		/* Exit handler address */
	unsigned int arg_count:8;	/* Number of arguments (never 0) */
	unsigned int :24;		/* Must be zero */
	int *status;			/* Address of exit status longword */
	long *(arg [1]);		/* Optional additional pointer arguments */
} system_exit_desc = { NULL, &exit_handler, 2, NULL, &final_status, &proc_desc };

system (line)

char *line;

{

	register int i;
	register char *cp;
	struct io$iosb iosb;
	register struct io$iosb *iosb_p = &iosb;
	int status = SS$_NORMAL;
	int completion_status = 0;
	long flags = CLI$M_NOWAIT | CLI$M_NOKEYPAD | CLI$M_NOCONTROL;
	char event_flag = FLAG;
	char buffer [BUFFER_LEN + 1];
	char command_line [COMMAND_LEN + 1];

/*		Various command line strings		*/

	static char ini_line [] = "$ SET NOON";
	static char bqt_line [] = "$ SET NOVERIFY";
	static char rpt_line [] = "$ WRITE SYS$OUTPUT \"''F$INTEGER ($STATUS)'\"";

/*		Get our Process information	*/

	if (first_pass || sub_exit_status)	{

/*		Communications Mailbox Items		*/

		char mailbox_base [MBX_PFX_LEN + 1];

/*		Process Information Items		*/

		char pid_qual_string [PID_QUAL_LEN + 1];
		char image_qual_string [IMAGE_QUAL_LEN + 1];
		struct itl$item_list sub_jpi_list [] = {
			{sizeof (sub_pid), JPI$_PID, &sub_pid, NULL},
			{NULL, NULL, NULL, NULL}
		};

		if (sub_exit_status)	{

/*		Complain about the party pooper			*/

			error_buf [i = substr (error_buf, "F-")] = 'W';
			cp = strzcpy (end_error_buf, "-SYSTEM-W-RESTARTING, Subprocess exited with a status of %X");
			cp += sprintf (cp, "%08X", sub_exit_status);
			strzcpy (cp, ", recreating subprocess");
			puts (error_buf);
			error_buf [i] = 'F';

/*		Get ready for another session		*/

			flush_mbx (input_mbx_chan);
			flush_mbx (output_mbx_chan);
			sub_exit_status = 0;

		}

		else	{

/*		First Pass Processing		*/

			sys$dclexh (&system_exit_desc);		/* desblk - exit handler control block address */

/*		Set up the complaint buffer		*/

			end_error_buf = strzcpy (strzcpy (&error_buf [1], cimageid (my_image)), 
						"-F-SYSERROR, SYSTEM routine internal error\n");

/*		Set up the PID qualifier string		*/
	
			sprintf (pid_qual_string, "_%04X", ((my_pid = getpid ()) & 0XFFFF));

/*		Set up the image qualifier string		*/

			cp = strncpy (image_qual_string, my_image, IMAGE_QUAL_LEN);

			for (i = 0; i < IMAGE_QUAL_LEN; i++)	{

				if (isalnum (*cp = toupper (*cp)))
					cp++;

				else
					break;

			}

			*cp = '\0';
			if (cp == image_qual_string)
				strzcpy (cp, "NO_IMAGE");			

/*		Set up the Sub-Process name string descriptor	*/

			cp = strzcpy (strzcpy (process_name, image_qual_string), pid_qual_string);
			proc_desc.dsc$w_length = cp - process_name;

/*		Set up the base Mailbox name string 	*/

			cp = strzcpy (strzcpy (mailbox_base, image_qual_string), pid_qual_string);
			*cp++ = '_';
			*cp = '\0';

/*		Bury any carcasses that may be lying around	*/

			status = sys$getjpiw (	event_flag,		/* efn    - event flag number */
						NULL,	 		/* pidadr - address of longword containing PID */
						&proc_desc,		/* prcnam - process name descriptor */
						&sub_jpi_list, 		/* itmlst - list of item descriptors */
						iosb_p,			/* iosb   - I/O Status Block address */
						NULL, 			/* astadr - AST service routine address */
						NULL);			/* astprm - AST parameter */

			if (check_status (&status, iosb_p))
				status = exit_handler (&status, &proc_desc);

			else if (status == SS$_NONEXPR)
				status = SS$_NORMAL;

/*		Create the INPUT mailbox	*/

			if (status == SS$_NORMAL)	{

				cp = strzcpy (strzcpy (input_mbx_string, mailbox_base), "INPUT");
				input_mbx_desc.dsc$w_length = cp - input_mbx_string;

				status = crembx (	input_mbx_string,	/* log_name    - mailbox logical name */
							NULL,		 	/* unit_number - mailbox unit number */
							&input_mbx_chan);	/* channel     - I/O channel */

			}

			if (status == SS$_NORMAL)	{	

/*		Create the OUTPUT mailbox	*/

				cp = strzcpy (strzcpy (output_mbx_string, mailbox_base), "OUTPUT");
				output_mbx_desc.dsc$w_length = cp - output_mbx_string;

				status = crembx (	output_mbx_string,	/* log_name    - mailbox logical name */
							NULL,			/* unit_number - mailbox unit number */
							&output_mbx_chan);	/* channel     - I/O channel */

			}

		}

/*		Create the subprocess		*/

		if (status == SS$_NORMAL)	{

			status = lib$spawn (	NULL,			/* cmdstr - descriptor */
						&input_mbx_desc,	/* infil  - descriptor for SYS$INPUT */ 
						&output_mbx_desc,	/* outfil - descriptor SYS$OUTPUT/ERROR */
						&flags,			/* flags  - address of control flags */
						&proc_desc,		/* prcnam - descriptor for desired name */
						&sub_pid,		/* pid    - longword to receive PID */
						&sub_exit_status,	/* cmpsts - longword to get exit status */
						NULL,			/* cmpefn - event flag number */
						&sub_exit,		/* astadr - AST service routine address */
						output_mbx_chan,	/* astprm - AST parameter */
						NULL,			/* prompt - prompt descriptor address */
						NULL);			/* cli    - CLI file descriptor address */

			if (status != SS$_NORMAL)	{

				strzcpy (end_error_buf, 
					"-SYSTEM-F-NOSPAWN, Unable to create the subprocess");
				complain (status, error_buf);

			}

		}

		if (status == SS$_NORMAL)	{

			status = issue_command (ini_line, sizeof (ini_line) - 1, input_mbx_chan, 
						output_mbx_chan, NULL, NULL);

			if (status == SS$_NORMAL)
				status = issue_command (bqt_line, sizeof (bqt_line) - 1, input_mbx_chan, 
							output_mbx_chan, NULL, NULL);

			if (status == SS$_NORMAL)
				first_pass = NO;

		}

		if (status != SS$_NORMAL)
			exit_handler (&status, &proc_desc);

	}

/*		Make the Subprocess do some work	*/

	if (status == SS$_NORMAL)	{

/*		Issue the command 	*/
	
		cp = strxcpy (strzcpy (command_line, "$ "), line, COMMAND_LEN - 1);

		if (cp != &command_line [2])	{

			status = issue_command (command_line, strlen (command_line), input_mbx_chan, output_mbx_chan, 
						&echo_output, stdout);

			if (sub_exit_status)				/* Subprocess freaked out */
				status = sub_exit_status;

			else if (status == SS$_NORMAL)	{

				status = issue_command (rpt_line, sizeof (rpt_line) - 1, input_mbx_chan, 
						output_mbx_chan, &interpret_status, &completion_status);
				if (status == SS$_NORMAL)
					status = completion_status & STS$M_SEVERITY;

			}

		}

	}

	return (status);

}

/*
/*	TITLE:                  ISSUE_COMMAND - ISSUE A COMMAND TO OUR SUBPROCESS AND 
/*						PROCESS WHATEVER OUTPUT IS PRODUCED
/*	SYSTEM:			COMMON DEC
/*	ENTRY POINT:		ISSUE_COMMAND
/*	SOURCE FILE:		SYSTEM.C
/*	PROGRAMMER:		Wayne E. Baisley
/*	SOFTWARE TREE:		CCLIB.STS
/*	DATE:			September 17, 1985
/*
/*	REVISIONS      DATE	  PROGRAMMER		DESCRIPTION
/*	---------    --------	--------------	-----------------------------
/*
/*	   0)	     09/17/85	W. E. Baisley	Original release.
/* */
	
static issue_command (command, size_of_command, input_mbx_chan, output_mbx_chan, processor, proc_arg)

char *command;
int size_of_command;
long input_mbx_chan;
long output_mbx_chan;
int (*processor) ();
int *proc_arg;

{

	int status = SS$_NORMAL;
	register int flushing = ((command == NULL) && (processor == NULL));
	struct io$iosb iosb;
	register struct io$iosb *iosb_p = &iosb;
	char event_flag = FLAG;
	char buffer [BUFFER_LEN + 1];
	int function_code = (flushing) ? IO$_READVBLK | IO$M_NOW : IO$_READVBLK;
	int (*attn_ast_routine) () = &end_file;

	if (!final_status)	{

/*		Issue the command if there is one	*/

		if (flushing)
			attn_ast_routine = NULL;

		else	{

			status = sys$qiow (	event_flag,		/* efn    - event flag */
						input_mbx_chan, 	/* chan   - I/O channel */
						IO$_WRITEVBLK |		/* func   - func'n code */
						IO$M_NOW,
						iosb_p,			/* iosb   - I/OSB addr */
						NULL,			/* astadr - AST routine */
						NULL,			/* astprm - AST parm */
						command,		/* p1     - buffer addr */
						size_of_command,	/* p2     - buffer size */
						NULL,			/* p3     - unused */
						NULL,			/* p4     - unused */
						NULL,			/* p5     - unused */
						NULL);			/* p6     - unused */

			if (!check_status (&status, iosb_p))	{

				strzcpy (end_error_buf, 
					"-ISSUE_COMMAND-F-FAILED, Unable to issue command to subprocess");
				complain (status, error_buf);

			}

		}

/*		Set up (or cancel) a completion AST so we'll know when the command completes	*/

		if (status == SS$_NORMAL)	{

			status = queue_read_attn_ast (	input_mbx_chan, 	/* Mailbox I/O channel */
							attn_ast_routine,	/* Attention AST routine */
							output_mbx_chan);	/* Attention AST parameter */


		}

	}

/*		Process whatever message(s) the subprocess emits	*/

	if (status == SS$_NORMAL)	{

		while (!(status = final_status))	{

			status = sys$qiow (	event_flag,		/* efn    - event flag */
						output_mbx_chan, 	/* chan   - I/O channel */
						function_code,		/* func   - func'n code */
						iosb_p,			/* iosb   - I/OSB addr */
						NULL,			/* astadr - AST routine */
						NULL,			/* astprm - AST parm */
						&buffer,		/* p1     - buffer addr */
						BUFFER_LEN,		/* p2     - buffer size */
						NULL,			/* p3     - unused */
						NULL,			/* p4     - unused */
						NULL,			/* p5     - unused */
						NULL);			/* p6     - unused */
	
			if (check_status (&status, iosb_p))	{

				if (processor)	{

					buffer [iosb_p->sb$w_count] = '\0';
					status = (*processor) (proc_arg, &buffer, status, iosb_p);
					if (!check_status (&status, iosb_p))
						break;

				}

				else
					continue;

			}

			else if (status == SS$_ENDOFFILE)	{

				status = SS$_NORMAL;

				if (((iosb_p->sb$l_2nd == my_pid)	&&
				     (!flushing))			||
				    (!iosb_p->sb$l_2nd))
					break;

			}

			else	{

				strzcpy (end_error_buf, 
					"-ISSUE_COMMAND-F-READERR, Unable to read output from subprocess");
				complain (status, error_buf);
				break;

			}

		}

	}

	return (status);

}

/*
/*	TITLE:                  ECHO_OUTPUT - COPY OUTPUT FROM OUR SUBPROCESS
/*					      TO OUTPUT
/*	SYSTEM:			COMMON DEC
/*	ENTRY POINT:		ECHO_OUTPUT
/*	SOURCE FILE:		SYSTEM.C
/*	PROGRAMMER:		Wayne E. Baisley
/*	SOFTWARE TREE:		CCLIB.STS
/*	DATE:			September 17, 1985
/*
/*	REVISIONS      DATE	  PROGRAMMER		DESCRIPTION
/*	---------    --------	--------------	-----------------------------
/*
/*	   0)	     09/17/85	W. E. Baisley	Original release.
/* */
	
static echo_output (output, buffer, status, iosb_p)

register FILE *output;
register char *buffer;
int status;
struct io$iosb *iosb_p;

{

	fputs (buffer, output);
	fputs ("\n", output);
	return (status);

}

/*
/*	TITLE:                  INTERPRET_STATUS - INTERPRET THE STATUS FROM THE LAST COMMAND
/*	SYSTEM:			COMMON DEC
/*	ENTRY POINT:		INTERPRET_STATUS
/*	SOURCE FILE:		SYSTEM.C
/*	PROGRAMMER:		Wayne E. Baisley
/*	SOFTWARE TREE:		CCLIB.STS
/*	DATE:			September 10, 1985
/*
/*	REVISIONS      DATE	  PROGRAMMER		DESCRIPTION
/*	---------    --------	--------------	-----------------------------
/*
/*	   0)	     09/10/85	W. E. Baisley	Original release.
/*
/*	   1)	     09/24/85	W. E. Baisley	Ignore zero-length buffers and 
/*						those that don't start with a number.
/* */
	
static interpret_status (completion_status, buffer, status, iosb_p)

register int *completion_status;
register char *buffer;
int status;
register struct io$iosb *iosb_p;

{

	if (isdigit (*buffer))
		*completion_status = atol (buffer);
	else
		*completion_status = SS$_ENDOFFILE;

	return (status);

}

/*
/*	TITLE:                  QUEUE_READ_ATTN_AST - QUEUE A MAILBOX ATTENTION AST
/*	SYSTEM:			COMMON DEC
/*	ENTRY POINT:		QUEUE_READ_ATTN_AST
/*	SOURCE FILE:		SYSTEM.C
/*	PROGRAMMER:		Wayne E. Baisley
/*	SOFTWARE TREE:		CCLIB.STS
/*	DATE:			September 10, 1985
/*
/*	REVISIONS      DATE	  PROGRAMMER		DESCRIPTION
/*	---------    --------	--------------	-----------------------------
/*
/*	   0)	     09/10/85	W. E. Baisley	Original release.
/*
/*	   1)	     09/25/85	W. E. Baisley	Modify error mesage to indicate 
/*						whether AST is being set or cleared.
/* */
	
static queue_read_attn_ast (mbx_chan, ast_rtn, ast_parm)

long mbx_chan;
int (*ast_rtn) ();
int ast_parm;

{

	int status = SS$_NORMAL;
	struct io$iosb iosb;
	register struct io$iosb *iosb_p = &iosb;
	char event_flag = FLAG;
	register char *cp;

	status = sys$qiow (	event_flag,		/* efn    - event flag */
				mbx_chan,	 	/* chan   - I/O channel */
				IO$_SETMODE |		/* func   - func'n code */
				IO$M_READATTN,
				iosb_p,			/* iosb   - I/OSB addr */
				NULL,			/* astadr - AST routine */
				NULL,			/* astprm - AST parm */
				ast_rtn,		/* p1     - Attention AST routine */
				ast_parm,		/* p2     - Attention AST parm */
				PSL$C_USER,		/* p3     - AST access mode */
				NULL,			/* p4     - unused */
				NULL,			/* p5     - unused */
				NULL);			/* p6     - unused */

	if (!check_status (&status, iosb_p))	{

		cp = strzcpy (end_error_buf, "-QUEUE_READ_ATTN_AST-F-NO");
		cp = strzcpy (cp, (ast_rtn) ? "SET" : "CLR");
		cp = strzcpy (end_error_buf, "ATTN, Unable to ");
		cp = strzcpy (cp, (ast_rtn) ? "set" : "clear");
		strzcpy (cp, " attention AST");
		complain (status, error_buf);

	}

	return (status);

}

/*
/*	TITLE:                  END_FILE - WRITE END-OF-FILE TO A MAILBOX
/*	SYSTEM:			COMMON DEC
/*	ENTRY POINT:		END_FILE
/*	SOURCE FILE:		SYSTEM.C
/*	PROGRAMMER:		Wayne E. Baisley
/*	SOFTWARE TREE:		CCLIB.STS
/*	DATE:			July 25, 1984
/*
/*	REVISIONS      DATE	  PROGRAMMER		DESCRIPTION
/*	---------    --------	--------------	-----------------------------
/*
/*	   0)	     07/25/84	W. E. Baisley	Original release.
/*
/* */
	
static end_file (mbx_chan)

long mbx_chan;

{

	register int status;
	struct io$iosb iosb;

	status = sys$qiow (	NULL,			/* efn    - event flag number */
				mbx_chan, 		/* chan   - I/O channel */
				IO$_WRITEOF |		/* func   - I/O function code */
				IO$M_NOW,
				&iosb,			/* iosb   - I/O Status Block address */
				NULL,			/* astadr - AST service routine address */
				NULL,			/* astprm - AST parameter */
				NULL,			/* p1     - unused */
				NULL,			/* p2     - unused */
				NULL,			/* p3     - unused */
				NULL,			/* p4     - unused */
				NULL,			/* p5     - unused */
				NULL);			/* p6     - unused */

	return (status);

}

/*
/*	TITLE:                  EXIT_HANDLER - CLEAN UP AFTER OURSELF
/*	SYSTEM:			COMMON DEC
/*	ENTRY POINT:		EXIT_HANDLER
/*	SOURCE FILE:		SYSTEM.C
/*	PROGRAMMER:		Wayne E. Baisley
/*	SOFTWARE TREE:		CCLIB.STS
/*	DATE:			September 9, 1985
/*
/*	REVISIONS      DATE	  PROGRAMMER		DESCRIPTION
/*	---------    --------	--------------	-----------------------------
/*
/*	   0)	     09/09/85	W. E. Baisley	Original release.
/*
/* */
	
static exit_handler (status, proc_desc)

int *status;
register struct dsc$descriptor_s *proc_desc;

{

	int my_status = SS$_NOPRIV;				/* Start with confidence */

	if (proc_desc)	{

		if (proc_desc->dsc$w_length)	{

			my_status = sys$delprc (NULL, proc_desc);

			if ((my_status != SS$_NORMAL) && (my_status != SS$_NONEXPR))	{

				strzcpy (strzcpy (end_error_buf, "-EXIT_HANDLER-F-CANTKILL, Unable to delete subprocess "), 
					proc_desc->dsc$a_pointer);
				complain (my_status, error_buf);

			}

		}

	}

	return (my_status);

}

/*
/*	TITLE:                  SUB_EXIT - DETECT THE SUBPROCESS' EXIT
/*	SYSTEM:			COMMON DEC
/*	ENTRY POINT:		SUB_EXIT
/*	SOURCE FILE:		SYSTEM.C
/*	PROGRAMMER:		Wayne E. Baisley
/*	SOFTWARE TREE:		CCLIB.STS
/*	DATE:			September 13, 1985
/*
/*	REVISIONS      DATE	  PROGRAMMER		DESCRIPTION
/*	---------    --------	--------------	-----------------------------
/*
/*	   0)	     09/13/85	W. E. Baisley	Original release.
/*
/* */
	
static sub_exit (mbx_chan)

long mbx_chan;

{

	end_file (mbx_chan);			/* Make sure we wake up */
	end_file (mbx_chan);
	end_file (mbx_chan);
	end_file (mbx_chan);
	return;

}
