726 lines
18 KiB
C
726 lines
18 KiB
C
/* $XFree86: xc/programs/xterm/vms.c,v 1.2 2003/10/27 01:07:58 dickey Exp $ */
|
|
|
|
/* vms.c
|
|
*
|
|
* This module contains the VMS version of the routine SPAWN (from the module
|
|
* MAIN.C) and the routines that do IO to the pseudo terminal.
|
|
*
|
|
* Modification History:
|
|
* Stephan Jansen 1-Mar-1990 Original version
|
|
* Hal R. Brand 5-Sep-1990 Added code to propagate DECW$DISPLAY
|
|
* Aaron Leonard 11-Sep-1990 Fix string descriptor lengths
|
|
* Stephan Jansen 2-Dec-1991 Modify to use new Pseudo terminal drivers
|
|
* (patterned after photo.c by Forrest A. Kenney)
|
|
* Patrick Mahan 7-Jan-1991 Removed reference to <dvidef.h> from VMS.C
|
|
* Forced device type to be VT102 since that is
|
|
* what we are emulating.
|
|
*/
|
|
|
|
#include <libdef.h>
|
|
#include <lnmdef.h>
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "xterm.h"
|
|
#include "data.h"
|
|
#include "vms.h"
|
|
|
|
#define PTD$C_SEND_XON 0 /* Pseudo Terminal Driver event */
|
|
#define PTD$C_SEND_BELL 1
|
|
#define PTD$C_SEND_XOFF 2
|
|
#define PTD$C_STOP_OUTPUT 3
|
|
#define PTD$C_RESUME_OUTPUT 4
|
|
#define PTD$C_CHAR_CHANGED 5
|
|
#define PTD$C_ABORT_OUTPUT 6
|
|
#define PTD$C_START_READ 7
|
|
#define PTD$C_MIDDLE_READ 8
|
|
#define PTD$C_END_READ 9
|
|
#define PTD$C_ENABLE_READ 10
|
|
#define PTD$C_DISABLE_READ 11
|
|
#define PTD$C_MAX_EVENTS 12
|
|
|
|
#define BUFFERS 6
|
|
#define PAGE 512
|
|
|
|
typedef struct tt_buffer
|
|
{
|
|
unsigned int flink;
|
|
unsigned int blink;
|
|
short int status;
|
|
short int length;
|
|
char data[VMS_TERM_BUFFER_SIZE];
|
|
} TT_BUF_STRUCT;
|
|
|
|
TT_BUF_STRUCT *tt_w_buff;
|
|
struct q_head _align(QUADWORD) buffer_queue = (0,0);
|
|
struct q_head _align(QUADWORD) read_queue = (0,0);
|
|
|
|
static char tt_name[64];
|
|
static $DESCRIPTOR (tt_name_desc, &tt_name);
|
|
|
|
static char ws_name[64];
|
|
static $DESCRIPTOR (ws_name_desc, &ws_name);
|
|
|
|
static struct tt_char {
|
|
char class;
|
|
char type;
|
|
short int page_width;
|
|
char characteristics[3];
|
|
char length;
|
|
int extended;
|
|
} tt_mode, tt_chars, orig_tt_chars;
|
|
|
|
struct mem_region
|
|
{
|
|
TT_BUF_STRUCT *start;
|
|
TT_BUF_STRUCT *end;
|
|
} ret_addr;
|
|
|
|
int read_stopped = FALSE;
|
|
int write_stopped = FALSE;
|
|
|
|
int tt_width;
|
|
int tt_length;
|
|
int tt_changed;
|
|
int tt_pasting=FALSE; /* drm */
|
|
int tt_new_output=FALSE; /* Cleared by flushlog(), set whenever something new
|
|
goes to the screen through tt_write */
|
|
|
|
int trnlnm(char *in,int id,char *out);
|
|
int tt_write(char *tt_write_buf,int size);
|
|
void spawn (void);
|
|
|
|
static void tt_echo_ast(TT_BUF_STRUCT *buff_addr);
|
|
static void tt_read_ast(TT_BUF_STRUCT *buff_addr);
|
|
|
|
/*
|
|
static void tt_start_read(void);
|
|
*/
|
|
void tt_start_read(void);
|
|
int tt_read(char *buffer);
|
|
static void send_xon(void);
|
|
static void send_xoff(void);
|
|
static void send_bell(void);
|
|
static void char_change(void);
|
|
static void freeBuff (TT_BUF_STRUCT *buff_addr);
|
|
TT_BUF_STRUCT *getBuff(void);
|
|
static void CloseDown(int exit_status);
|
|
static void mbx_read_ast(void);
|
|
static void mbx_read(void);
|
|
|
|
|
|
|
|
#define DESCRIPTOR(name,string) struct dsc$descriptor_s name = \
|
|
{ strlen(string), DSC$K_DTYPE_T, DSC$K_CLASS_S, string }
|
|
|
|
int trnlnm(char *in, int id, char *out)
|
|
{
|
|
int status, num, len, attr = LNM$M_CASE_BLIND, foo = id;
|
|
short outlen;
|
|
struct itemlist
|
|
{
|
|
short buffer_length;
|
|
short item_code;
|
|
char *buffer_addr;
|
|
int *return_length;
|
|
} itmlst[] =
|
|
{
|
|
4 , LNM$_INDEX , &foo, 0,
|
|
255, LNM$_STRING , out , &outlen,
|
|
4 , LNM$_MAX_INDEX, &num, &len,
|
|
0 , 0
|
|
};
|
|
DESCRIPTOR(lognam,in);
|
|
DESCRIPTOR(tabnam,"LNM$DCL_LOGICAL");
|
|
|
|
status = sys$trnlnm(&attr,&tabnam,&lognam,0,itmlst);
|
|
if(status != SS$_NORMAL) return(-1); /* error status */
|
|
out[outlen] = 0; /* terminate the output string */
|
|
return(++num); /* return number of translations */
|
|
}
|
|
|
|
static int pty;
|
|
static int Xsocket;
|
|
|
|
void spawn (void)
|
|
{
|
|
int status;
|
|
static $DESCRIPTOR (dtime, "0 00:00:00.01");
|
|
static int delta[2];
|
|
register TScreen *screen = &term->screen;
|
|
static struct IOSB iosb;
|
|
static unsigned int flags;
|
|
static unsigned int uic;
|
|
static char imagename[64];
|
|
static int privs;
|
|
static $DESCRIPTOR(device, "FTA0:");
|
|
static int type;
|
|
static int class;
|
|
static int devdepend;
|
|
static int mem_size;
|
|
int i;
|
|
|
|
/* if pid and mbx_chan are nonzero then close them in CloseDown() */
|
|
pid = 0;
|
|
mbx_chan = 0;
|
|
|
|
status = SYS$EXPREG (BUFFERS, &ret_addr, 0, 0);
|
|
if(!(status & SS$_NORMAL)) lib$signal(status);
|
|
|
|
tt_w_buff = (char *)ret_addr.end - PAGE + 1;
|
|
|
|
/* use one buffer for writing, the reset go in the free buffer queue */
|
|
for(i=0; i < BUFFERS-1; i++)
|
|
{
|
|
freeBuff((char *)ret_addr.start +i*PAGE);
|
|
}
|
|
|
|
/* avoid double MapWindow requests, for wm's that care... */
|
|
XtSetMappedWhenManaged( screen->TekEmu ? XtParent(tekWidget) :
|
|
XtParent(term), False );
|
|
/* Realize the Tek or VT widget, depending on which mode we're in.
|
|
If VT mode, this calls VTRealize (the widget's Realize proc) */
|
|
XtRealizeWidget (screen->TekEmu ? XtParent(tekWidget) :
|
|
XtParent(term));
|
|
|
|
/* get the default device characteristics of the pseudo terminal */
|
|
|
|
itemlist[0].buflen = 4;
|
|
itemlist[0].code = DVI$_DEVTYPE;
|
|
itemlist[0].buffer = &type;
|
|
itemlist[0].return_addr = &tt_name_desc.dsc$w_length;
|
|
|
|
itemlist[1].buflen = 4;
|
|
itemlist[1].code = DVI$_DEVCLASS;
|
|
itemlist[1].buffer = &class;
|
|
itemlist[1].return_addr = &tt_name_desc.dsc$w_length;
|
|
|
|
itemlist[2].buflen = 4;
|
|
itemlist[2].code = DVI$_DEVDEPEND;
|
|
itemlist[2].buffer = &devdepend;
|
|
itemlist[2].return_addr = &tt_name_desc.dsc$w_length;
|
|
|
|
itemlist[3].buflen = 4;
|
|
itemlist[3].code = DVI$_DEVDEPEND2;
|
|
itemlist[3].buffer = &tt_chars.extended;
|
|
itemlist[3].return_addr = &tt_name_desc.dsc$w_length;
|
|
|
|
itemlist[4].buflen = 0;
|
|
itemlist[4].code = 0;
|
|
|
|
|
|
status = sys$getdviw(0,0,&device,&itemlist,&iosb,0,0,0);
|
|
if(!(status & SS$_NORMAL)) lib$signal(status);
|
|
if(!(iosb.status & SS$_NORMAL)) lib$signal(iosb.status);
|
|
|
|
tt_chars.type = DT$_VT102; /* XTerm supports VT102 mode */
|
|
tt_chars.class = class;
|
|
tt_chars.page_width = screen->max_col+1;
|
|
tt_chars.length = screen->max_row+1;
|
|
|
|
/* copy the default char's along with the created window size */
|
|
|
|
bcopy(&devdepend, &tt_chars.characteristics, 3);
|
|
|
|
tt_chars.extended |= TT2$M_ANSICRT | TT2$M_AVO | TT2$M_DECCRT;
|
|
|
|
|
|
/* create the pseudo terminal with the proper char's */
|
|
status = ptd$create(&tt_chan,0,&tt_chars,12,0,0,0,&ret_addr);
|
|
if(!(status & SS$_NORMAL)) lib$signal(status);
|
|
|
|
|
|
/* get the device name of the Pseudo Terminal */
|
|
|
|
itemlist[0].buflen = 64;
|
|
itemlist[0].code = DVI$_DEVNAM;
|
|
itemlist[0].buffer = &tt_name;
|
|
itemlist[0].return_addr = &tt_name_desc.dsc$w_length;
|
|
|
|
/* terminate the list */
|
|
itemlist[1].buflen = 0;
|
|
itemlist[1].code = 0;
|
|
|
|
status = sys$getdviw(0,tt_chan,0,&itemlist,&iosb,0,0,0);
|
|
if(!(status & SS$_NORMAL)) CloseDown(status);
|
|
if(!(iosb.status & SS$_NORMAL)) CloseDown(iosb.status);
|
|
|
|
/*
|
|
* set up AST's for XON, XOFF, BELL and characteristics change.
|
|
*/
|
|
|
|
status = ptd$set_event_notification(tt_chan,&send_xon,0,0,PTD$C_SEND_XON);
|
|
if(!(status & SS$_NORMAL)) CloseDown(status);
|
|
|
|
status = ptd$set_event_notification(tt_chan,&send_xoff,0,0,PTD$C_SEND_XOFF);
|
|
if(!(status & SS$_NORMAL)) CloseDown(status);
|
|
|
|
status = ptd$set_event_notification(tt_chan,&send_bell,0,0,PTD$C_SEND_BELL);
|
|
if(!(status & SS$_NORMAL)) CloseDown(status);
|
|
|
|
status = ptd$set_event_notification(tt_chan,&char_change,0,0,PTD$C_CHAR_CHANGED);
|
|
if(!(status & SS$_NORMAL)) CloseDown(status);
|
|
|
|
/* create a mailbox for the detached process to detect hangup */
|
|
|
|
status = sys$crembx(0,&mbx_chan,ACC$K_TERMLEN,0,255,0,0);
|
|
if(!(status & SS$_NORMAL)) CloseDown(status);
|
|
|
|
|
|
/*
|
|
* get the device unit number for created process completion
|
|
* status to be sent to.
|
|
*/
|
|
|
|
itemlist[0].buflen = 4;
|
|
itemlist[0].code = DVI$_UNIT;
|
|
itemlist[0].buffer = &mbxunit;
|
|
itemlist[0].return_addr = 0;
|
|
|
|
/* terminate the list */
|
|
itemlist[1].buflen = 0;
|
|
itemlist[1].code = 0;
|
|
|
|
status = sys$getdviw(0,mbx_chan,0,&itemlist,&iosb,0,0,0);
|
|
if(!(status & SS$_NORMAL)) CloseDown(status);
|
|
if(!(iosb.status & SS$_NORMAL)) CloseDown(iosb.status);
|
|
|
|
|
|
tt_start_read();
|
|
|
|
/*
|
|
* find the current process's UIC so that it can be used in the
|
|
* call to sys$creprc
|
|
*/
|
|
itemlist[0].buflen = 4;
|
|
itemlist[0].code = JPI$_UIC;
|
|
itemlist[0].buffer = &uic;
|
|
itemlist[0].return_addr = 0;
|
|
|
|
/* terminate the list */
|
|
itemlist[1].buflen = 0;
|
|
itemlist[1].code = 0;
|
|
|
|
status = sys$getjpiw(0,0,0,&itemlist,0,0,0);
|
|
if(!(status & SS$_NORMAL)) CloseDown(status);
|
|
|
|
/* Complete a descriptor for the WS (DECW$DISPLAY) device */
|
|
|
|
trnlnm("DECW$DISPLAY",0,ws_name);
|
|
ws_name_desc.dsc$w_length = strlen(ws_name);
|
|
|
|
/* create the process */
|
|
/* Set sys$error to be the WS (DECW$DISPLAY) device. LOGINOUT */
|
|
/* has special code for DECWINDOWS that will: */
|
|
/* 1) do a DEFINE/JOB DECW$DISPLAY 'f$trnlnm(sys$error)' */
|
|
/* 2) then redefine SYS$ERROR to match SYS$OUTPUT! */
|
|
/* This will propogate DECW$DISPLAY to the XTERM process!!! */
|
|
/* Thanks go to Joel M Snyder who posted this info to INFO-VAX */
|
|
|
|
flags = PRC$M_INTER | PRC$M_NOPASSWORD | PRC$M_DETACH;
|
|
status = sys$creprc(&pid,&image,&tt_name_desc,&tt_name_desc,
|
|
&ws_name_desc,0,0,0,4,uic,mbxunit,flags);
|
|
if(!(status & SS$_NORMAL)) CloseDown(status);
|
|
|
|
|
|
/* hang a read on the mailbox waiting for completion */
|
|
mbx_read();
|
|
|
|
|
|
/* set time value and schedule a periodic wakeup (every 1/100 of a second)
|
|
* this is used to prevent the controlling process from using up all the
|
|
* CPU. The controlling process will hibernate at strategic points in
|
|
* the program when it is just waiting for input.
|
|
*/
|
|
|
|
status = sys$bintim(&dtime,&delta);
|
|
if (!(status & SS$_NORMAL)) CloseDown(status);
|
|
|
|
status = sys$schdwk(0,0,&delta,&delta);
|
|
if (!(status & SS$_NORMAL)) CloseDown(status);
|
|
|
|
|
|
/*
|
|
* This is rather funky, but it saves me from having to totally
|
|
* rewrite some parts of the code (namely in_put in module CHARPROC.C)
|
|
*/
|
|
pty = 1;
|
|
screen->respond = pty;
|
|
pty_mask = 1 << pty;
|
|
Select_mask = pty_mask;
|
|
X_mask = 1 << Xsocket;
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* This routine handles completion of write with echo. It takes the
|
|
* echo buffer and puts it on the read queue. It will then be processed
|
|
* by the routine tt_read. If the echo buffer is empty, it is put back
|
|
* on the free buffer queue.
|
|
*/
|
|
|
|
static void tt_echo_ast(TT_BUF_STRUCT *buff_addr)
|
|
{
|
|
int status;
|
|
|
|
if (buff_addr->length != 0)
|
|
{
|
|
status = LIB$INSQTI(buff_addr, &read_queue);
|
|
if((status != SS$_NORMAL) && (status != LIB$_ONEENTQUE))
|
|
{
|
|
CloseDown(status);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
freeBuff(buff_addr);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* This routine writes to the pseudo terminal. If there is a free
|
|
* buffer then write with an echo buffer completing asyncronously, else
|
|
* write syncronously using the buffer reserved for writing. All errors
|
|
* are fatal, except DATAOVERUN and DATALOST,these errors can be ignored.
|
|
|
|
CAREFUL! Whatever calls this must NOT pass more than VMS_TERM_BUFFER_SIZE
|
|
bytes at a time. This definition has been moved to VMS.H
|
|
|
|
*/
|
|
|
|
int tt_write(char *tt_write_buf, int size)
|
|
{
|
|
int status;
|
|
TT_BUF_STRUCT *echoBuff;
|
|
|
|
/* if writing stopped, return 0 until Xon */
|
|
if(write_stopped) return (0);
|
|
|
|
memmove(&tt_w_buff->data,tt_write_buf,size);
|
|
|
|
echoBuff = getBuff();
|
|
if (echoBuff != LIB$_QUEWASEMP)
|
|
{
|
|
status = PTD$WRITE (tt_chan, &tt_echo_ast, echoBuff,
|
|
&tt_w_buff->status, size,
|
|
&echoBuff->status, VMS_TERM_BUFFER_SIZE);
|
|
}
|
|
else
|
|
{
|
|
status = PTD$WRITE (tt_chan, 0, 0, &tt_w_buff->status, size, 0, 0);
|
|
}
|
|
if (status & SS$_NORMAL)
|
|
{
|
|
if ((tt_w_buff->status != SS$_NORMAL) &&
|
|
(tt_w_buff->status != SS$_DATAOVERUN) &&
|
|
(tt_w_buff->status != SS$_DATALOST))
|
|
{
|
|
CloseDown(tt_w_buff->status);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CloseDown(status);
|
|
}
|
|
|
|
return(size);
|
|
}
|
|
|
|
|
|
/*
|
|
* This routine is called when a read to the pseudo terminal completes.
|
|
* Put the newly read buffer onto the read queue. It will be processed
|
|
* and freed in the routine tt_read.
|
|
*/
|
|
|
|
static void tt_read_ast(TT_BUF_STRUCT *buff_addr)
|
|
{
|
|
int status;
|
|
|
|
if (buff_addr->status & SS$_NORMAL)
|
|
{
|
|
status = LIB$INSQTI(buff_addr, &read_queue);
|
|
if ((status != SS$_NORMAL) && (status != LIB$_ONEENTQUE))
|
|
{
|
|
CloseDown(status);
|
|
}
|
|
}
|
|
else
|
|
CloseDown(buff_addr->status);
|
|
|
|
tt_start_read();
|
|
sys$wake(0,0);
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* If there is a free buffer on the buffer queue then Start a read from
|
|
* the pseudo terminal, otherwise set a flag, the reading will be restarted
|
|
* in the routine freeBuff when a buffer is freed.
|
|
*/
|
|
|
|
void tt_start_read(void)
|
|
{
|
|
int status;
|
|
static int size;
|
|
TT_BUF_STRUCT *buff_addr;
|
|
|
|
buff_addr = getBuff();
|
|
if (buff_addr != LIB$_QUEWASEMP)
|
|
{
|
|
if(!tt_pasting){
|
|
status = PTD$READ (0, tt_chan, &tt_read_ast, buff_addr,
|
|
&buff_addr->status, VMS_TERM_BUFFER_SIZE);
|
|
if ((status & SS$_NORMAL) != SS$_NORMAL)
|
|
{
|
|
CloseDown(status);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
read_stopped = TRUE;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* Get data from the pseudo terminal. Return the data from the first item
|
|
* on the read queue, and put that buffer back onto the free buffer queue.
|
|
* Return the length or zero if the read queue is empty.
|
|
*
|
|
*/
|
|
|
|
int tt_read(char *buffer)
|
|
{
|
|
TT_BUF_STRUCT *read_buff;
|
|
int status;
|
|
int len;
|
|
|
|
status = LIB$REMQHI(&read_queue, &read_buff);
|
|
if(status == LIB$_QUEWASEMP){
|
|
return(0);
|
|
}
|
|
else if (status & SS$_NORMAL)
|
|
{
|
|
len = read_buff->length;
|
|
memmove(buffer,&read_buff->data,len);
|
|
freeBuff(read_buff);
|
|
tt_new_output=TRUE; /* DRM something will be written */
|
|
}
|
|
else
|
|
CloseDown(status);
|
|
|
|
return(len);
|
|
}
|
|
|
|
|
|
/*
|
|
* if xon then it is safe to start writing again.
|
|
*/
|
|
|
|
static void send_xon(void)
|
|
{
|
|
write_stopped = FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
* If Xoff then stop writing to the pseudo terminal until you get Xon.
|
|
*/
|
|
static void send_xoff(void)
|
|
{
|
|
write_stopped = TRUE;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Beep the terminal to let the user know data will be lost because
|
|
* of too much data.
|
|
*/
|
|
|
|
static void send_bell(void)
|
|
{
|
|
Bell();
|
|
}
|
|
|
|
/*
|
|
* if the pseudo terminal's characteristics change, check to see if the
|
|
* page size changed. If it did, resize the widget, otherwise, ignore
|
|
* it! This routine just gets the new term dimensions and sets a flag
|
|
* to indicate the term chars have changed. The widget gets resized in
|
|
* the routine in_put in the module CHARPROC.C. You cant resize the
|
|
* widget in this routine because this is an AST and X is not reenterent.
|
|
*/
|
|
|
|
static void char_change(void)
|
|
{
|
|
int status;
|
|
|
|
/*
|
|
* Dont do anything if in Tek mode
|
|
*/
|
|
|
|
if(!(term->screen.TekEmu))
|
|
{
|
|
status = sys$qiow(0,tt_chan,IO$_SENSEMODE,0,0,0,&tt_mode,8,0,0,0,0);
|
|
if(!(status & SS$_NORMAL)) CloseDown(status);
|
|
|
|
if((term->screen.max_row != tt_mode.length) ||
|
|
(term->screen.max_col != tt_mode.page_width))
|
|
{
|
|
tt_length = tt_mode.length;
|
|
tt_width = tt_mode.page_width;
|
|
|
|
tt_changed = TRUE;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Put a free buffer back onto the buffer queue. If reading was
|
|
* stopped for lack of free buffers, start reading again.
|
|
*/
|
|
|
|
static void freeBuff (TT_BUF_STRUCT *buff_addr)
|
|
{
|
|
int ast_stat;
|
|
int status;
|
|
|
|
ast_stat = SYS$SETAST(0);
|
|
if (!read_stopped)
|
|
{
|
|
LIB$INSQHI(buff_addr, &buffer_queue);
|
|
}
|
|
else
|
|
{
|
|
status = PTD$READ (0, tt_chan, &tt_read_ast, buff_addr,
|
|
&buff_addr->status, VMS_TERM_BUFFER_SIZE);
|
|
if (status & SS$_NORMAL)
|
|
{
|
|
read_stopped = FALSE;
|
|
}
|
|
else
|
|
{
|
|
CloseDown(status);
|
|
}
|
|
}
|
|
if (ast_stat == SS$_WASSET) ast_stat = SYS$SETAST(1);
|
|
}
|
|
|
|
|
|
/*
|
|
* return a free buffer from the buffer queue.
|
|
*/
|
|
|
|
TT_BUF_STRUCT *getBuff(void)
|
|
{
|
|
int status;
|
|
TT_BUF_STRUCT *buff_addr;
|
|
|
|
status = LIB$REMQHI(&buffer_queue, &buff_addr);
|
|
if (status & SS$_NORMAL)
|
|
{
|
|
return(buff_addr);
|
|
}
|
|
else
|
|
{
|
|
return(status);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Close down and exit. Kill the detached process (if it still
|
|
* exists), deassign mailbox channell (if assigned), cancel any
|
|
* waiting IO to the pseudo terminal and delete it, exit with any
|
|
* status information.
|
|
*/
|
|
|
|
static void CloseDown(int exit_status)
|
|
{
|
|
int status;
|
|
|
|
/* if process has not terminated, do so now! */
|
|
if(pid != 0)
|
|
{
|
|
status = sys$forcex(&pid,0,0);
|
|
if(!(status & SS$_NORMAL)) lib$signal(status);
|
|
}
|
|
|
|
/* if mbx_chan is assigned, deassign it */
|
|
if(mbx_chan != 0)
|
|
{
|
|
sys$dassgn(mbx_chan);
|
|
}
|
|
|
|
/* cancel pseudo terminal IO requests */
|
|
status = ptd$cancel(tt_chan);
|
|
if(!(status & SS$_NORMAL)) lib$signal(status);
|
|
|
|
/* delete pseudo terminal */
|
|
status = ptd$delete(tt_chan);
|
|
if(!(status & SS$_NORMAL)) lib$signal(status);
|
|
|
|
if(!(exit_status & SS$_NORMAL)) lib$signal(exit_status);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* This routine gets called when the detached process terminates (for
|
|
* whatever reason). The mailbox buffer has final exit status. Close
|
|
* down and exit.
|
|
*/
|
|
|
|
static void mbx_read_ast(void)
|
|
{
|
|
int status;
|
|
|
|
pid = 0;
|
|
|
|
status = mbx_read_iosb.status;
|
|
if (!(status & SS$_NORMAL)) CloseDown(status);
|
|
|
|
status = (unsigned long int) mbx_buf.acc$l_finalsts;
|
|
if (!(status & SS$_NORMAL)) CloseDown(status);
|
|
|
|
CloseDown(1);
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* This routine starts a read on the mailbox associated with the detached
|
|
* process. The AST routine gets called when the detached process terminates.
|
|
*/
|
|
|
|
static void mbx_read(void)
|
|
{
|
|
int status;
|
|
static int size;
|
|
|
|
size = ACC$K_TERMLEN;
|
|
status = sys$qio(0,mbx_chan,
|
|
IO$_READVBLK,
|
|
&mbx_read_iosb,
|
|
&mbx_read_ast,
|
|
0,
|
|
&mbx_buf,
|
|
size,0,0,0,0);
|
|
|
|
if (!(status & SS$_NORMAL)) CloseDown(status);
|
|
|
|
return;
|
|
}
|