Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!uunet!seismo!rutgers!labrea!decwrl!decvax!ucbvax!ENGVAX.SCG.HAC.COM!KVC From: KVC@ENGVAX.SCG.HAC.COM (Kevin Carosso) Newsgroups: comp.os.vms Subject: CMU pseudo-terminal drivers (part 1 of 3) [DCL archive format] Message-ID: <8707200032.AA02560@ucbvax.Berkeley.EDU> Date: Thu, 16-Jul-87 19:50:00 EDT Article-I.D.: ucbvax.8707200032.AA02560 Posted: Thu Jul 16 19:50:00 1987 Date-Received: Mon, 20-Jul-87 03:44:10 EDT Sender: daemon@ucbvax.BERKELEY.EDU Distribution: world Organization: The ARPA Internet Lines: 872 $ show default $ check_sum = 1515454846 $ write sys$output "Creating 000_README.TXT" $ create 000_README.TXT $ DECK/DOLLARS="$*$*EOD*$*$" These files make up a pseudo terminal driver for VAX/VMS. This driver runs under VMS version 4.x. It will not work under VMS prior to 4. See PSEUDO.DOC for documentation and NOTES.TXT for my additional comments and observations. This new version fixes up several major bugs, including: o ^S^Y system crasher o randomly mungedand characters o SHOW DEVICE stack dumps o system crashes due to attempted use of the TPA0: device o terminal device name changed from PTAn: to TPAn: because VMS uses PTA for MSCP tapes. This driver was originally developed at Carnegie-Mellon University and has made the rounds before as the CMU PTY driver. /Kevin Carosso kvc@engvax.scg.hac.com Hughes Aircraft Co. or kvc%engvax@oberon.usc.edu December 9, 1986 $*$*EOD*$*$ $ checksum 000_README.TXT $ if checksum$checksum .ne. check_sum then - $ write sys$output "Checksum failed, file probably corrupted" $ check_sum = 1780435178 $ write sys$output "Creating DESCRIP.MMS" $ create DESCRIP.MMS $ DECK/DOLLARS="$*$*EOD*$*$" ! Build the pseudo-terminal utility, PYDRIVER and TPDRIVER. ! INCLUDE pub_root:[lib.mms]include.mms DESTDIR = $(PRIVDIR) distribution_files = 000_readme.txt, descrip.mms, driver.opt, notes.txt, - pseudo.doc, pty.pas, pydriver.mar, tpdriver.mar MFLAGS = /NOLIST build : PYDRIVER.EXE TPDRIVER.EXE @ WRITE SYS$OUTPUT "Build finished." install : build $(DESTDIR)pydriver.exe $(DESTDIR)tpdriver.exe $ write sys$output "Installation finished" distribute : zz_pty_dist.com $ write sys$output "DCL archive complete: $(MMS$SOURCE)" TPDRIVER.EXE : TPDRIVER.OBJ - LINK TPDRIVER.OBJ,DRIVER.OPT/OPT,SYS$SYSTEM:SYS.STB/SELECT PYDRIVER.EXE : PYDRIVER.OBJ - LINK PYDRIVER.OBJ,DRIVER.OPT/OPT,SYS$SYSTEM:SYS.STB/SELECT $(DESTDIR)pydriver.exe : pydriver.exe $ copy $< $@ $(DESTDIR)tpdriver.exe : tpdriver.exe $ copy $< $@ zz_pty_dist.com : $(distribution_files) $ @pub:archive $(MMS$TARGET) "$(MMS$SOURCE_LIST)" $*$*EOD*$*$ $ checksum DESCRIP.MMS $ if checksum$checksum .ne. check_sum then - $ write sys$output "Checksum failed, file probably corrupted" $ check_sum = 1702060495 $ write sys$output "Creating DRIVER.OPT" $ create DRIVER.OPT $ DECK/DOLLARS="$*$*EOD*$*$" base=0 $*$*EOD*$*$ $ checksum DRIVER.OPT $ if checksum$checksum .ne. check_sum then - $ write sys$output "Checksum failed, file probably corrupted" $ check_sum = 238513379 $ write sys$output "Creating NOTES.TXT" $ create NOTES.TXT $ DECK/DOLLARS="$*$*EOD*$*$" These notes should be considered an addition to the documentation to be found in PSEUDO.DOC. These notes document some enhancements I have made to the drivers as well as some caveats I have found. First of all, I want to grant credit to the original authors of the driver, they are listed at the beginning of the two source files. In private correspondence with Dale Moore at CMU, he has chosen to release the driver to the public domain. There have been various incarnations of this driver in the past. I started with a version that was modified to run under VMS V4 and cleaned it up and made CONNECT/DISCONNECT and HANGUP work consistently. I also changed the device name of the terminal device from PTAn: to TPAn: because VMS now uses PTA0: for MSCP tapes. The drivers have been tested on VMS V4.0 through V4.5. Load the two drivers as PYA0: and TPA0:. Assigning a channel to PYA0: will create a PYAn: and a TPAn: pseudo-terminal pair (the unit numbers just go up). Anything you write to that channel appears on the TP as if typed at a terminal. Any output to the terminal TPAn: is available to be read from PYAn:. On output, the devices do flow control between one another and all buffering. You can just read, for example, with a 100 char buffer from PY and the read will complete with whatever number of characters the QIO to the TP terminal had, anywhere from 1 to MAXBUF. If the QIO to the TP had more chars than your read buffer, it'll just fill the read buffer and return, and you can get the rest on the next read. On input, it is possible to overrun the TP device's terminal type-ahead buffer, as it is with a real terminal. If you assign a mailbox with the PYAn: device (use LIB$ASN_WTH_MBX when assigning the channel to PYA0:) you will get an MSG$_TRMHANGUP message in the mailbox whenever the terminal is hung-up. This occurs when a process deassigns the last channel to the device, just as a HANGUP will on terminals with modem signals. You may ignore the hangup message if you choose and continue to use the device after the message. Should you deassign all channels to the PYAn: device, a hangup will be forced on any process using the TPAn: device. Just like dropping carrier on a modem line. If the pseudo-terminal is in use by an interactive process and has an associated virtual terminal, the process will be disconnected, otherwise the interactive process will be logged out. To enable virtual terminals on pseudo-terminals, you must have the TT2$M_DISCONNECT bit set in the system default terminal characteristics (TTY_DEFCHAR2 in SYSGEN). Note that, just as with normal VMS terminals, you will only get a VTAn: if the line has the DISCONNECT terminal characteristic before you log into it, and only if you use LOGINOUT to start a process on the terminal. Sending a into the pseudo-terminal device will start up LOGINOUT as it would on a real terminal. There is currently one minor known bug in the drivers, a side-effect of the driver being cautious in order to prevent possible problems. If you have a virtual terminal associated with the pseudo-terminal, and you deassign the last channel to the control device (the PY device) then a DISCONNECT is forced on any process on the TP and both devices should be deleted. Currently, the TP will not disappear, though the PY will and the TP will be marked as OFFLINE. This is because I rely on VMS to do the actual delete of the device and it appears that virtual terminals screw up the way device reference counts work, so VMS never gets around to deleting the device. It is marked for delete, so anything you do (I like SHOW TERM TPA53:, for example) will cause it to disappear. I could fix this by zapping the device explicitly after forcing the DISCONNECT, however I am not convinced that someone, somewhere, won't try to reference the UCB and thus cause bad things to occur. Note that it DOES get deleted correctly if you do not have a virtual terminal associated with the TP or if you have no processes active on the TP when the PY and TP are to be deleted. These two cases are generally the norm. I am currently considering a few enhancements: o It should be possible to set the TP terminal characteristics through the PY device, so the controlling program can set them. o The TP device driver should notify the controlling program (via the associated mailbox) whenever the TP terminal characteristics are changed in case applications need to know such things. o There should be a mechanism, again utilizing the associated mailbox, for the controlling application to be notified when the TP's typeahead buffer fills. I need to think about the ramifications of changing device characteristics on TTDRIVER unexpectedly, however, before I make the first change. If you need to set characteristics of the terminal device right now, you must assign a channel to the TP device and use a SETMODE QIO then deassign the channel before giving the TP to another process. You will get a HANGUP message in the associated mailbox when you deassign if the HANGUP attribute was set on the device. You can ignore this message, however, and go ahead and use the device. You cannot set characteristics of the master device. This used to be allowed, though it had no purpose, and it crashes the system (at least under V4). /Kevin Carosso kvc%engvax.UUCP@oberon.usc.edu Hughes Aircraft Co. December 9, 1986 $*$*EOD*$*$ $ checksum NOTES.TXT $ if checksum$checksum .ne. check_sum then - $ write sys$output "Checksum failed, file probably corrupted" $ check_sum = 1110109988 $ write sys$output "Creating PSEUDO.DOC" $ create PSEUDO.DOC $ DECK/DOLLARS="$*$*EOD*$*$" 1. PTY Driver This chapter describes the use of the VAX/VMS Pseudo Terminal Driver as implemented Carnegie-Mellon University Computer Science Department. Additional information about VMS device drivers and the VMS operating system interface can be found in VAX/VMS I/O User's Guide, and in VAX/VMS System Service Reference Manual. 1.1 PTY Driver Features and Capabilities Pseudo terminals (or PTYs) are virtual terminals in the system. Unlike normal terminals where the I/O is actually done with a physical device, PTY's I/O has no interface to any physical device. In this way they are much like mailboxes. 1.1.1 Concept of Control and Terminal Device A single PTY consists of two devices, a control and a terminal device. The terminal device is the device that acts like a terminal. The control device on VMS is named ``PYAx:''. For example, a PTY control device could be named ``PYA1:''. The terminal device portion of the PTY is name ``TPAx:''. The terminal device ``TPA1:'' is the mate to the control device ``PYA1:''. Similarly, the control device ``PYA5:'' is the mate to the terminal device ``TPA5:''. 1.1.1.1 Similarities Between PTYs and Terminals The terminal portion of a PTY behaves very much like a regular VAX/VMS terminal. The terminal portion of a PTY has - Type-ahead - Specifiable or default line terminators - Special operating modes, such as NOECHO and PASSALL - American National Standard escape sequence detection - Terminal/mailbox interaction - Terminal control characters such as Sontrol-S and Control-Q for starting and stopping output, Control-O for discarding output, and all other special characters that are handled by the VAX/VMS terminal driver. - Limited full-duplex operation(simultaneously active read and write requests) 1.1.1.2 Differences Between PTYs and Terminals The difference between a VAX/VMS terminal and the terminal portion of a PTY is where the input comes from and where the output goes to. On a VAX/VMS terminal, the input comes from an actual terminal and the output goes to an actual terminal. On a PTY the input comes from the control device and the output goes to the control device. In order to simulate someone typing at the terminal device ``TPA5:'' we must write to the control device ``PYA5:''. In order to read what has been typed out to the terminal device ``TPA5:'' we must read from the control device ``PYA5:''. PTYs are like terminals that only software can access. There is no buffering of the input on the control device. It is possible to fill up the terminal device's typeahead buffer by writing large amounts of data to the control device. PTYs are virtual devices. When allocating a PTY, they behave much like mailboxes or network devices. To allocate a PTY, simply allocate the first one ('PYA0:'). The allocating routine will be create a new PTY and assign it to you. The PTY will be deallocated when no process is referencing the device. 1.1.1.3 Uses of PTYs There is no device from DEC which suffices for remote logins when using non-DECnet protocols. The remote terminal driver expects the remote node to do the local line editing. This includes delete, control-o, control-s, control-q, and much other stuff. PTYs handle the local line editing locally. When the line editing is done locally, the remote machine has to know much less about VMS and its terminal handling conventions. 1.2 Installing PTYs In VAX/VMS V3.0, several pieces of software support the terminal interface. The hardware independent portion is SYS$SYSTEM:TTDRIVER.EXE. This version of PTYs does not require any changes or patches to this code. There are other pieces of software for particular pieces of hardware. The code in SYS$SYSTEM:DZDRIVER.EXE is the device driver required for DZ11's and DZ32's. The code in SYS$SYSTEM:YCDRIVER.EXE is the device driver required for DMF32's. PTY drivers consist of two device drivers, TPDRIVER.EXE for the terminal portion of the PTY's, and PYDRIVER.EXE for the control portion. 1.2.1 Compiling Sources There are several pieces of source code that make up PTY drivers. PYDRIVER.MAR is the source for the control portion. TPDRIVER.MAR is the source for the terminal portion. The commands for compiling and linking the devices are: $ ! Compile the drivers $ MACRO /LIST /OBJECT TPDRIVER.MAR+SYS$LIBRARY:LIB/LIBRARY $ MACRO /LIST /OBJECT PYDRIVER.MAR+SYS$LIBRARY:LIB/LIBRARY $ ! Link the drivers $ LINK /SHARE /MAP /FULL /CROSS - TPDRIVER,SYS$SYSTEM:SYS.STB/SELECTIVE,SYS$INPUT:/OPTION BASE=0 $ LINK /SHARE /MAP /FULL /CROSS - PYDRIVER,SYS$SYSTEM:SYS.STB/SELECTIVE,SYS$INPUT:/OPTION BASE=0 1.2.2 Installing the Devices To load a PTY, login to a privileged account and issue the following commands. $ RUN SYS$SYSTEM:SYSGEN CONNECT TPA0/NOADAPTER/DRIVER=device:[directory]TPDRIVER CONNECT PYA0/NOADAPTER/DRIVER=device:[directory]PYDRIVER You may want to build a command file which installs the devices at boot time by modifying SYS$MANAGER:SYSTARTUP.COM. Don't try to use TPB0 or PYB0. The code is not built to handle these. It is only built to handle the PYA and TPA control and terminal devices. 1.3 Device Information User processes can obtain terminal and control device information by using the $GETDVI, $GETCHN and $GETDEV system services (see VAX/VMS System Services Reference Manual). It is recommended that new programs make use of the $GETDVI and $GETDVIW system services. 1.3.1 PTY Terminal Device Dependent Information The information returned about a terminal device is in the same format as information returned about a regular VAX/VMS terminal. By only looking at the information returned from $GETCHN and $GETDEV system services, it is impossible to tell the difference between a PTY terminal device and an actual terminal device. 1.3.2 PTY Control Device Dependent Information When applied to a PTY control device, $GETCHN return information in the format as show in Figure 1-1. 31 24 23 16 15 8 7 0 ----------------------------------------------------- | Device Characteristics | ----------------------------------------------------- | Buffer Size | Type | Class | ----------------------------------------------------- | Unused | TP Unit Number | ----------------------------------------------------- Figure 1-1: PTY Control Device Dependent Information The first longword contains device-independent data. The second and third longwords contain device-dependent data. 1.3.2.1 Device Characteristics The characteristics of the the PTY control device (PYA) can be found by either using the first longword returned by the $GETDEV and $GETCHN system services, or by using the item code DVI$ DEVCHAR to the $GETDVI system service. A PTY control device has the following characteristics. - DEV$M AVL - On line and available - DEV$M IDV - Capable of input - DEV$M ODV - Capable of output - DEV$M REC - Record oriented A PTY control device does not have the following characteristics. - DEV$M CCL - Carriage Control - DEV$M TRM - Terminal Device 1.3.2.2 Buffer Size Also returned from $GETDVI by using item code DVI$ DEVBUFSIZ. 1.3.2.3 Device Type The device type is DT$ PY. Since a PTY is a nonstandard device, you will probably not find the correct macros, literals or constants for this device type. This field should have a value of 0. Also returned from $GETDVI by using item code DVI$ DEVTYPE. 1.3.2.4 Device Class The device class is DC$ PY. Since a PTY seems to be such an odd creature, this field should be FF in hex, or 177 in octal. Also returned from $GETDVI by using item code DVI$ DEVCLASS. 1.3.2.5 PT Unit Number The unit number is unit number of the associated PTY terminal device. The unit number is also returned as the low sixteen bits in DVI$ DEVDEPEND by $GETDVI. 1.4 PTY Function Codes The function codes for the terminal device portion of a PTY are exactly the same as those for regular VAX/VMS terminals. For more information on VAX/VMS terminal I/O see VAX/VMS I/O User's Guide. The basic function of the control portion of a PTY are read, write and set mode or characteristics. A user does not need to have assigned the PTY terminal device in order to do I/O operations on the PTY control device. If the terminal device has type ahead enabled, sending the right characters at the control device will send a message to OPCOM to start running SYS$SYSTEM:LOGINOUT.EXE on the terminal device. 1.4.1 Read The basic purpose of a PTY control device read is to transfer data from the output buffer of the PTY terminal device to a user specified buffer. There are three read functions which a user can apply to a PTY control device. - IO$ READVBLK - Read virtual block - IO$ READLBLK - Read logical block - IO$ READPBLK - Read physical block A read is complete if either of the below conditions occur: - The user specified buffer is full - At least one character is available from the PTY terminal device The read function codes can take the following device/function dependent arguments: - P1 = The starting virtual address of the buffer that is to receive the data read - P2 = The size of the buffer that is to receive the data read in bytes - P3, P4, P5, P6 = ignored 1.4.2 Write The basic purpose of a PTY control device write is to transfer data from the user specified buffer to the typeahead buffer of the PTY terminal device. There are three write functions which a user can apply to a PTY control device. - IO$ WRITEVBLK - write virtual block - IO$ WRITELBLK - write logical block - IO$ WRITEPBLK - write physical block The write function codes can take the following device/function dependent arguments: - P1 = The starting virtual address of the buffer that is to be written to the PTY terminal device - P2 = The number of bytes that are to be sent - P3, P4, P5, P6 = Ignored 1.4.3 Set Mode and Set Characteristics The Set Mode function affects the mode and temporary characteristics of the associated PTY control device. Set Mode is a logical I/O function and requires no privilege. A single function code is provided: - IO$ SETMODE The Set Charateristics function affects the permanent characteristics of the associated PTY control device. Set Characteristics is a physical I/O function and requires the privilege necessary to perform physical I/O. A single function code is provided: - IO$ SETCHAR These functions take the following device/function dependent arguments if no function modifiers are specified: - P1 = address of characteristics buffer - P2, P3, P4, P5, P6 = ignored The P1 argument points to a quadword block, as shown in Figure 1-2. 31 24 23 16 15 8 7 0 ----------------------------------------------------- | Buffer Size | Type | Class | ----------------------------------------------------- | Unused | ----------------------------------------------------- Figure 1-2: Set Mode Characteristics Buffer 1.4.3.1 Function Modifiers Function Modifiers to the control device currently do not affect the state or accessibility of terminal device. You cannot change the mode or characteristics of the terminal device by adding function modifiers to the I/O routines for the control device. An earlier version of PTYdrivers supported this feature. This feature has not yet been added to this version. 1.4.4 Sense Mode and Sense Characterisitics The two function codes to sense the mode of the PTY control device are: - IO$ SENSEMODE - IO$ SENSECHAR The IO$ SENSEMODE function returns the process-associated, that is temporary, characteristics of the PTY control device. The IO$ SENSECHAR function returns the permanent characteristics of the PTY control device. The IO$ SENSEMODE function is a logical function and requires no privilege. The IO$ SENSECHAR function is a physical function and requires the privilege necessary to perform physical I/O. These function codes take the following device/function dependent. - P1 = address of the quadword characteristics buffer - P2, P3, P4, P5, P6 = ignored The P1 argument points to a quadword block which is the same format as the Set Mode Characteristics Buffer, shown in Figure 1-2 1.4.5 I/O Status Block The I/O status block formats for read, write, set mode and sense mode I/O functions are shown in Figures 1-3 and 1-4. 31 24 23 16 15 8 7 0 ----------------------------------------------------- | Byte Count | Status | ----------------------------------------------------- | Unused | ----------------------------------------------------- Figure 1-3: IOSB Contents - Read and Write Function 31 24 23 16 15 8 7 0 ----------------------------------------------------- | Unused | Status | ----------------------------------------------------- | Unused | ----------------------------------------------------- Figure 1-4: IOSB Contents - Set and Sense Mode and Characteristics Functions The status indicates the succes or failure of the specified operation. Below are possible values for the status field: - SS$ ABORT - The operation was canceled by the Cancel I/O on Channel ($CANCEL) system service. Applicable only if the drive was actively involved in an operation. - SS$ NORMAL - Successful Completion - SS$ ACCVIO - The specified buffer is not accessible to the specified process 1.5 Possible Improvements and Bugs Watch the error counts on the devices. Occasionally, a PTY terminal device might get a timeout. Perhaps, it is not executing at a sufficient IPL. Somehow, we aren't entering the startio routine soon after the UCB$V_TIM bit is set in UCB$W_STS. It may be useful for the associated mailbox of the PY device to receive a message every time the stop, start, abort, resume, xoff, or xon routine is called. This would permit programs that control the PY device to determine when to slow down the data rate, or abort the output in the buffers which have already been read. Table of Contents 1. PTY Driver 2 1.1 PTY Driver Features and Capabilities 2 1.1.1 Concept of Control and Terminal Device 2 1.1.1.1 Similarities Between PTYs and Terminals 2 1.1.1.2 Differences Between PTYs and Terminals 2 1.1.1.3 Uses of PTYs 2 1.2 Installing PTYs 2 1.2.1 Compiling Sources 2 1.2.2 Installing the Devices 2 1.3 Device Information 2 1.3.1 PTY Terminal Device Dependent Information 2 1.3.2 PTY Control Device Dependent Information 2 1.3.2.1 Device Characteristics 2 1.3.2.2 Buffer Size 2 1.3.2.3 Device Type 2 1.3.2.4 Device Class 3 1.3.2.5 TP Unit Number 3 1.4 PTY Function Codes 3 1.4.1 Read 3 1.4.2 Write 3 1.4.3 Set Mode and Set Characteristics 3 1.4.3.1 Function Modifiers 3 1.4.4 Sense Mode and Sense Characterisitics 3 1.4.5 I/O Status Block 3 1.5 Possible Improvements and Bugs 3 List of Figures Figure 1-1: PTY Control Device Dependent Information 2 Figure 1-2: Set Mode Characteristics Buffer 3 Figure 1-3: IOSB Contents - Read and Write Function 3 Figure 1-4: IOSB Contents - Set and Sense Mode and Characteristics 3 Functions $*$*EOD*$*$ $ checksum PSEUDO.DOC $ if checksum$checksum .ne. check_sum then - $ write sys$output "Checksum failed, file probably corrupted" $ check_sum = 1443436246 $ write sys$output "Creating PTY.PAS" $ create PTY.PAS $ DECK/DOLLARS="$*$*EOD*$*$" (* Simple program to converse with the pseudo-terminal control device. *) [inherit ('SYS$LIBRARY:STARLET')] program PTY; const buffer_size = 256; CTRL_BACKSLASH = chr (28); type string = varying [256] of char; unsigned_byte = [byte] 0..255; unsigned_word = [word] 0..65535; characteristic_buffer = packed record dev_class, dev_type : unsigned_byte; width : unsigned_word; charbits, extended_bits : unsigned; end; status_block = packed record status, count, terminator, terminator_size : unsigned_word; end; var stat : integer; mbx_chan, tt_chan, pty_chan : [static, volatile] unsigned_word; input_char : [static, volatile] char; buffer : packed array [1..buffer_size] of char; mbx_buffer : [static, volatile] packed array [1..40] of char; term_chars, old_term_chars : [static, volatile] characteristic_buffer; in_iosb, out_iosb, mbx_iosb : [static, volatile] status_block; exit_descriptor : [static] packed record flink : unsigned; handler : unsigned; argnum : integer; reason : ^integer; end := (0, 0, 1, nil); message : [static, volatile] string := ''(13, 10, 7)'Got a mailbox message'(13, 10); {-----------------------------------------------------------------------------} [external] function LIB$ASN_WTH_MBX (DEVNAM : [class_s] packed array [l1..u1:integer] of char; MAXMSG, BUFQUO : integer; var DEVCHAN, MBXCHAN : [volatile] unsigned_word ) : integer; extern; (* * CLEANUP is our exit handler. It resets the terminal characteristics. *) [unbound] function Cleanup (reason : integer) : integer; var stat : integer; iosb : status_block; begin (* Cleanup *) Cleanup := reason; stat := $QIOW (CHAN := tt_chan, FUNC := IO$_SETMODE, P1 := old_term_chars, P2 := size (old_term_chars)); if not odd (stat) then Cleanup := stat; end; (* Cleanup *) [asynchronous, unbound] procedure Set_asynch_mbx_input; forward; (* * MBX_INPUT_AST is the AST handler invoked whenever we get something in * the associated mailbox. *) [asynchronous, unbound] procedure Mbx_input_AST; var stat : integer; iosb : status_block; begin (* Mbx_input_AST *) if not odd (mbx_iosb.status) then $EXIT (mbx_iosb.status); stat := $QIOW (CHAN := tt_chan, FUNC := IO$_WRITEVBLK, IOSB := iosb, P1 := message.body, P2 := message.length); if not odd (stat) then $EXIT (stat); if not odd (iosb.status) then $EXIT (iosb.status); Set_asynch_mbx_input; end; (* mbx_input_AST *) (* * SET_ASYNCH_MBX_INPUT issues an asynchronous read on the terminal. *) procedure Set_asynch_mbx_input; var stat : integer; begin (* Set_asynch_mbx_input *) stat := $QIO (CHAN := mbx_chan, FUNC := IO$_READVBLK, IOSB := mbx_iosb, ASTADR := mbx_input_AST, P1 := mbx_buffer, P2 := size (mbx_buffer)); if not odd (stat) then $EXIT (stat); end; (* Set_asynch_mbx_input *) [asynchronous, unbound] procedure Set_asynch_input; forward; (* * INPUT_AST is the AST handler invoked whenever we get something in * from the terminal. Just ship it to the PTY. *) [asynchronous, unbound] procedure Input_AST; var stat : integer; begin (* Input_AST *) if not odd (in_iosb.status) then $EXIT (in_iosb.status); if input_char = CTRL_BACKSLASH then $EXIT (SS$_NORMAL); stat := $QIOW (CHAN := pty_chan, FUNC := IO$_WRITEVBLK, IOSB := in_iosb, P1 := input_char, P2 := 1); if not odd (stat) then $EXIT (stat); if not odd (in_iosb.status) then $EXIT (in_iosb.status); Set_asynch_input; end; (* Input_AST *) (* * SET_ASYNCH_INPUT issues an asynchronous read on the terminal. *) procedure Set_asynch_input; var stat : integer; begin (* Set_asynch_input *) stat := $QIO (CHAN := tt_chan, FUNC := IO$_READVBLK, IOSB := in_iosb, ASTADR := Input_AST, P1 := input_char, P2 := 1); if not odd (stat) then $EXIT (stat); end; (* Set_asynch_input *) begin (* PTY *) stat := LIB$ASN_WTH_MBX (DEVNAM := 'PYA0:', MAXMSG := size (mbx_buffer), BUFQUO := 2 * size (mbx_buffer), DEVCHAN := pty_chan, MBXCHAN := mbx_chan); if not odd (stat) then $EXIT (stat); Set_asynch_mbx_input; stat := $ASSIGN (CHAN := tt_chan, DEVNAM := 'TT'); if not odd (stat) then $EXIT (stat); (* Get terminal characteristics. *) stat := $QIOW (CHAN := tt_chan, FUNC := IO$_SENSEMODE, P1 := term_chars, P2 := size (term_chars)); if not odd (stat) then $EXIT (stat); if term_chars.dev_class <> DC$_TERM then $EXIT (SS$_IVDEVNAM); old_term_chars := term_chars; (* declare exit handler so that terminal chars are restored *) exit_descriptor.handler := iaddress (Cleanup); new (exit_descriptor.reason); stat := $DCLEXH (DESBLK := exit_descriptor); if not odd (stat) then $EXIT (stat); (* * Set terminal characteristics we need: * PASSTHRU, NOECHO, NOTTSYNC, NOHOSTSYNC *) with term_chars do begin extended_bits := UOR (extended_bits, TT2$M_PASTHRU); charbits := UOR (charbits, TT$M_NOECHO); charbits := UAND (charbits, UNOT (TT$M_TTSYNC)); charbits := UAND (charbits, UNOT (TT$M_HOSTSYNC)); end; stat := $QIOW (CHAN := tt_chan, FUNC := IO$_SETMODE, P1 := term_chars, P2 := size (term_chars)); if not odd (stat) then $EXIT (stat); Set_asynch_input; repeat stat := $QIOW (CHAN := pty_chan, FUNC := IO$_READVBLK, IOSB := out_iosb, P1 := buffer, P2 := size (buffer)); if not odd (stat) then $EXIT (stat); if not odd (out_iosb.status) then $EXIT (out_iosb.status); stat := $QIOW (CHAN := tt_chan, FUNC := IO$_WRITEVBLK, IOSB := out_iosb, P1 := buffer, P2 := out_iosb.count); if not odd (stat) then $EXIT (stat); if not odd (out_iosb.status) then $EXIT (out_iosb.status); until false; end. (* PTY *) $*$*EOD*$*$ $ checksum PTY.PAS $ if checksum$checksum .ne. check_sum then - $ write sys$output "Checksum failed, file probably corrupted" $ exit