.TITLE PHOTO - Record terminal interaction
.IDENT /1.00/
;++
; Title:
; PHOTO - Record terminal interaction
;
; Facility:
; General VMS utilities
;
; Abstract:
; PHOTO is a VMS utility for recording exactly all characters
; sent to and received from an interactive session. It works
; in conjunction with the PTY pseudo devices created by
; the PTYDRIVER. When PHOTO is initiated, a subprocess is
; spawned which then executes all of the user's commands.
; The main process continues to run PHOTO, which logs all
; input and output to a file. The ^A character toggles logging
; to the file. PHOTO is terminated by terminating the subprocess
; with a POP or LOGOUT.
;
; Associated mailboxes are used to drive I/O on the user's terminal
; and the subprocesses "terminal" (PTY). Reads are posted on the
; mailboxes with AST routines specified. The AST routines are
; then called with "unsolicited data" messages whenever there is data
; for either terminal. The AST routine does zero timeout reads
; to obtain all the data available in the terminal's typeahead buffer.
;
; This program must be assembled with DEV$SSG:[SSG.GLG.SMAC]SMAC.MLB.
;
; Environment:
; Native Mode. Requires that PTY0 pseudo device be CONNECTED
; on system.
;
; Author:
; Gary L. Grebus, Creation date: 3-Jan-1984 02:07:09
;
; Battelle Columbus Labs
;
; Modified by:
;
; 1.01 - Gary L. Grebus, 5-Mar-1984 01:34:13
; Fixed exit handler. Implemented time stamp and buffering
; of log file lines.
;--
.PAGE
.SBTTL Symbol definitions
; System symbols
$IODEF ; I/O symbol definitions
$NAMDEF ; RMS NAM block symbols
$DCDEF ; Device class symbols
$MSGDEF ; System mailbox message definitions
$DVIDEF ; $GETDVI request codes
$TTDEF ; Terminal characteristics
$TT2DEF
; Local symbols
RCV_BUFFER_SZ=512 ; Size of input buffers
XMIT_BUFFER_SZ=512 ; Size of output buffers
MB_BUFFER_SZ=20 ; Size of mailbox buffers
MB_BYTLM_SZ=2*MB_BUFFER_SZ ; Amount of space used for mailbox msgs
PTY_NAME_SZ=15 ; Size for PTY device names
LINE_BUFFER_SZ=140 ; Size of the output line buffer
STAMP_SZ=10 ; Size of time stamp
ASCII_LF=^X0A ; Line Feed (Record terminator)
ASCII_CR=^X0D
.PAGE
.SBTTL Local macros
.MACRO SIGNAL_ERROR MESSAGE,PARAM,?L1
BLBS R0,L1
.IF BLANK,
SIGNAL CODE1=#MESSAGE,CODE2=R0
.IFF
SIGNAL CODE1=#MESSAGE,F1=,CODE2=R0
.ENDC
L1:
.ENDM SIGNAL_ERROR
.MACRO RWDATA_SECTION
.PSECT RWDATA RD,WRT,NOSHR,NOEXE,LONG
.ENDM RWDATA_SECTION
.MACRO CODE_SECTION
.PSECT CODE RD,NOWRT,EXE,SHR,LONG
.ENDM CODE_SECTION
.Macro REQLIST
.Endm REQLIST
.Macro ITEM code, buff_addr, buff_len = 4, ret_len_addr = 0
.word buff_len
.word code
.long buff_addr
.long ret_len_addr
.Endm ITEM
.Macro REQEND
.long 0
.Endm REQEND
.PAGE
.SBTTL Read/write data
RWDATA_SECTION
; Read/write data
; Global TTY data structures
TTY_CHAN:
.BLKW 1 ; Channel number for terminal I/O
TTY_IOSB_IN:
.BLKQ 1 ; IOSB for terminal input
TTY_IOSB_OUT:
.BLKQ 1 ; IOSB for terminal output
TTY_RCV_BUFFER:
.BLKB RCV_BUFFER_SZ ; Buffer for terminal input
TTY_XMIT_BUFFER:
.BLKB XMIT_BUFFER_SZ ; Buffer for terminal output
TTY_DEVNAME:
.ASCID /SYS$COMMAND/ ; Logical device name for terminal
TTY_MB_CHAN:
.BLKW 1 ; Channel for TTY associated mailbox
TTY_MB_IOSB:
.BLKQ 1 ; IOSB for TTY associated mailbox
TTY_MB_BUFFER:
.BLKB MB_BUFFER_SZ ; Buffer for TTY associated mailbox
TTY_OLD_CHAR:
.BLKB 12 ; Old TTY device characteristics
; Global PTY data structures
PTY_DEVNAME:
.BLKW 1
.WORD 0
.ADDRESS PTY_DEVNAME_BUF ; Skeleton descriptor
PTY_DEVNAME_BUF:
.BLKB PTY_NAME_SZ ; Buffer for name
PTY_CHAN:
.BLKW 1 ; Channel number for PTY
PTY_IOSB_IN:
.BLKQ 1 ; IOSB for PTY input
PTY_IOSB_OUT:
.BLKQ 1 ; IOSB for PTY output
PTY_RCV_BUFFER:
.BLKB RCV_BUFFER_SZ ; Buffer for PTY input
PTY_XMIT_BUFFER:
.BLKB XMIT_BUFFER_SZ ; Buffer for PTY output
PTY_MB_CHAN:
.BLKW 1 ; Channel for PTY associated mailbox
PTY_MB_IOSB:
.BLKQ 1 ; IOSB for PTY associated mailbox
PTY_MB_BUFFER:
.BLKB MB_BUFFER_SZ ; Buffer for PTY associated mailbox
; Misc. main program data
TOGGLE_CHAR:
.LONG ^X01 ; Flag character that toggles logging
TIME_STAMP_QUAL:
.ASCID /TIME_STAMP/ ; Qualifier name for /TIME_STAMP
TIME_STAMP_FLAG:
.BLKL 1 ; Flag that /TIME_STAMP was specified
LOGGING_FLAG:
.BLKL 1 ; Flag that logging is toggled on.
SUBPR_PID:
.BLKL 1 ; PID of our subprocess
SUBPR_END_STATUS:
.BLKL 1 ; Termination status of subprocess
EXIT_BLOCK:
.BLKL 1
.ADDRESS CLEANUP
.LONG 1
.ADDRESS EXIT_STATUS ; Exit handler block
EXIT_STATUS:
.BLKL 1 ; Place for exit status
; Global log file data structures
.ALIGN LONG
LOG_FAB:
$FAB DNM=<.LOG>,-
ORG=SEQ,-
RFM=VAR,-
SHR=,-
FAC=PUT ; FAB for log file
LOG_RAB:
$RAB FAB=LOG_FAB,-
ROP= ; RAB for log file
STAMP_TIME:
.BYTE ASCII_CR ; Stamp starts with CR
.BLKB STAMP_SZ-1 ; Space for time stamp if used
LINE_BUFFER:
.BLKB LINE_BUFFER_SZ ; Buffer to accumulate a line
LINE_NEXTCH:
.BLKL 1 ; Pointer to next free character slot
LINE_COUNT:
.BLKL 1 ; Count of characters in line
STAMP_DESC:
.LONG STAMP_SZ-1
.ADDRESS STAMP_TIME+1 ; Descriptor for time stamp buffer
; Static QIO parameter lists
TTYMB_QIO_LIST:
$QIO FUNC=,-
IOSB=TTY_MB_IOSB,-
ASTADR=TTY_DATA_AST,-
P1=TTY_MB_BUFFER,-
P2=MB_BUFFER_SZ
PTYMB_QIO_LIST:
$QIO FUNC=,-
IOSB=PTY_MB_IOSB,-
ASTADR=PTY_DATA_AST,-
P1=PTY_MB_BUFFER,-
P2=MB_BUFFER_SZ
TTYOUT_QIO_LIST:
$QIO FUNC=,-
IOSB=TTY_IOSB_OUT,-
P1=TTY_XMIT_BUFFER
PTYOUT_QIO_LIST:
$QIO FUNC=IO$_WRITEVBLK,-
IOSB=PTY_IOSB_OUT,-
P1=PTY_XMIT_BUFFER
TTYTA_QIO_LIST:
$QIO FUNC=,-
IOSB=TTY_IOSB_IN,-
P1=TTY_RCV_BUFFER,-
P2=RCV_BUFFER_SZ,-
P3=0
PTYTA_QIO_LIST:
$QIO FUNC=,-
IOSB=PTY_IOSB_IN,-
P1=PTY_RCV_BUFFER,-
P2=RCV_BUFFER_SZ,-
P3=0
.PAGE
.SBTTL PHOTO - Main Program
CODE_SECTION
.ENTRY PHOTO,0
; Declare an exit handler to cleanup accidents
$DCLEXH_S -
DESBLK=EXIT_BLOCK
; Setup the devices involved
CALL SETUP_TTY
CALL SETUP_PTY
; Find out if the /TIME_STAMP qualifier was specified
CALL G^CLI$PRESENT TIME_STAMP_QUAL
EXTZV #0,#1,R0,TIME_STAMP_FLAG ; Set the flag if present
CLRL LINE_COUNT ; Clear count for line buffer
MOVAL LINE_BUFFER,LINE_NEXTCH ; and init next character pointer
CALL CREATE_LOG ; Create the log file
SIGNAL CODE1=#PHOTO_STARTLOG,F1=#0 ; Send message that we are
; logging
; Clear typeahead from the terminal. This fixes a problem which sometimes
; causes the first character received by from the terminal to be displayed
; twice
$QIOW_S -
CHAN=TTY_CHAN,-
FUNC=#,-
IOSB=TTY_IOSB_IN,-
P1=TTY_RCV_BUFFER,-
P2=#RCV_BUFFER_SZ
IF THEN
MOVZWL TTY_IOSB_IN,R0 ; If QIO worked, get I/O status
IF THEN
MOVZWL #SS$_NORMAL,R0 ; Timeout is really normal here
ENDIF
ENDIF
SIGNAL_ERROR -
PHOTO_QIOREAD, TTY_DEVNAME ; Check for QIO error
; Post initial reads on both the PTY and TTY associated mailboxes
JSB POST_TTY_MBREAD
JSB POST_PTY_MBREAD
CALL START_SUBPR ; Spawn a subprocess
; Now we go to sleep, and all the work happens at AST level.
; When we wake up again, it will be because the subprocess has died.
$HIBER_S
SIGNAL CODE1=#PHOTO_STOPLOG,F1=#0 ; Send message that we are done
; logging
CALL CLEANUP ; Cleanup all pending I/O and channels
MOVZWL #SS$_NORMAL,R0 ; Return success
RET
.PAGE
.SBTTL SETUP_PTY - Setup PTY device
;++
; Functional Description:
; This routine obtains a channel on a PTY device and associates
; a mailbox. It stores the channel numbers into the QIO parameter lists.
;
; Calling Sequence:
; CALLS #0,SETUP_PTY
;
; Input Parameters: NONE
;
; Output Parameters: NONE
;
; Implicit Inputs: NONE
;
; Implicit Outputs:
; PTY_DEVNAME, PTY_CHAN, PTYxx_QIO_LIST, PTY_MB_CHAN
;
; Procedures called:
; LIB$ASN_WTH_MBX
;
; Completion Status:
; NONE - Signals any errors
;
; Side Effects:
; Causes a PTY pair to be created
;
;--
RWDATA_SECTION
PTY_TEMPLATE:
.ASCID /_PTY0:/ ; PTY template device
PTY_NAME_DVI:
REQLIST
ITEM DVI$_DEVNAM,PTY_DEVNAME_BUF,PTY_NAME_SZ,-
PTY_DEVNAME ; and device name
REQEND
PTY_IOSB_SET:
.BLKQ 1 ; IOSB for SETMODE operation
PTY_NEW_CHAR:
.BLKB 12 ; New PTY characteristics
CODE_SECTION
.ENTRY SETUP_PTY,^M
MOVAB PTY_TEMPLATE,R2 ; Address of device name
PUSHL #MB_BUFFER_SZ ; Need to pass these by reference
MOVL SP,R3
PUSHL #MB_BYTLM_SZ
MOVL SP,R4
CALL G^LIB$ASN_WTH_MBX -
(R2),(R3),-
(R4),-
PTY_CHAN,PTY_MB_CHAN ; Assign the channels
SIGNAL_ERROR -
PHOTO_ASGERR, (R2) ; Check for error
$GETDVI_S -
CHAN=PTY_CHAN,-
ITMLST=PTY_NAME_DVI ; Get PTY device name
SIGNAL_ERROR -
PHOTO_GETDVI ; Check for error
MOVL TTY_OLD_CHAR,-
PTY_NEW_CHAR ; Copy old TTY characteristics
MOVQ TTY_OLD_CHAR+4,-
PTY_NEW_CHAR+4
BICL2 #TT2$M_MODHANGUP!TT2$M_SETSPEED,-
PTY_NEW_CHAR+8 ; We might not have priv to change
; these
$QIOW_S -
CHAN=PTY_CHAN,-
FUNC=#IO$_SETMODE,-
IOSB=PTY_IOSB_SET,-
P1=PTY_NEW_CHAR,-
P2=#12 ; Propagate terminal characteristics
; to the PTY
IF THEN
MOVZWL PTY_IOSB_SET,R0 ; If QIO worked, get I/O status
ENDIF
SIGNAL_ERROR -
PHOTO_QIOSET,PTY_DEVNAME ; Check for error
MOVZWL PTY_MB_CHAN,-
PTYMB_QIO_LIST+QIO$_CHAN ; Store channel in QIO lists
MOVZWL PTY_CHAN,-
PTYOUT_QIO_LIST+QIO$_CHAN
MOVZWL PTY_CHAN,-
PTYTA_QIO_LIST+QIO$_CHAN
RET
.PAGE
.SBTTL SETUP_TTY - Setup TTY device
;++
; Functional Description:
; This routine assigns a channel on the current SYS$COMMAND
; which must be a terminal and on an associated mailbox. The channel
; numbers are stored into the QIO parameter lists. The terminal is
; placed into PASSALL mode.
;
; Calling Sequence:
; CALLS #0,SETUP_TTY
;
; Input Parameters: NONE
;
; Output Parameters: NONE
;
; Implicit Inputs:
; TTY_DEVNAME
;
; Implicit Outputs:
; TTY_CHAN, TTYxx_QIO_LIST, TTY_OLD_CHAR
;
; Procedures called:
; LIB$ASN_WTH_MBX, SYS$GETDVI
;
; Completion Status:
; NONE - Errors are signalled
;
; Side Effects: NONE
;
;--
RWDATA_SECTION
GETDVI_LIST: ; Request list for $GETDVI
REQLIST
ITEM DVI$_DEVCLASS, DEVCLASS
REQEND
DEVCLASS:
.BLKL 1 ; Buffer for $GETDVI result
TTY_NEW_CHAR:
.BLKB 12 ; New TTY characteristics
CODE_SECTION
.ENTRY SETUP_TTY,^M
PUSHL #MB_BUFFER_SZ ; Need to pass these by reference
MOVL SP,R3
PUSHL #MB_BYTLM_SZ
MOVL SP,R4
CALL G^LIB$ASN_WTH_MBX -
TTY_DEVNAME,(R3),-
(R4),-
TTY_CHAN,TTY_MB_CHAN ; Assign the channels
SIGNAL_ERROR -
PHOTO_ASGERR, TTY_DEVNAME ; Check for errors
$GETDVI_S -
CHAN=TTY_CHAN,-
ITMLST=GETDVI_LIST ; Get device class for SYS$COMMAND
IF THEN
SIGNAL -
CODE1=#PHOTO_NOTTERM ; If not a terminal, punt
ENDIF
; Put the terminal into PASSALL/NOECHO mode
$QIOW_S -
CHAN=TTY_CHAN,-
FUNC=#IO$_SENSEMODE,-
P1=TTY_OLD_CHAR,-
P2=#12 ; Get current characteristics
SIGNAL_ERROR -
PHOTO_QIOSENSE,-
TTY_DEVNAME ; Check for errors
MOVQ TTY_OLD_CHAR,TTY_NEW_CHAR ; Copy them
BISL2 #TT$M_NOECHO!TT$M_PASSALL,-
TTY_NEW_CHAR+4 ; Set NOECHO and PASSALL
$QIOW_S -
CHAN=TTY_CHAN,-
FUNC=#IO$_SETMODE,-
P1=TTY_NEW_CHAR,-
P2=#12 ; Modify device characteristics
SIGNAL_ERROR -
PHOTO_QIOSET,TTY_DEVNAME ; Check for errors
MOVZWL TTY_MB_CHAN,-
TTYMB_QIO_LIST+QIO$_CHAN ; Fixup QIO parameter lists
MOVZWL TTY_CHAN,-
TTYOUT_QIO_LIST+QIO$_CHAN
MOVZWL TTY_CHAN,-
TTYTA_QIO_LIST+QIO$_CHAN
RET
.PAGE
.SBTTL START_SUBPR - Spawn a subprocess
;++
; Functional Description:
; This routine is called to spawn a subprocess running the DCL
; CLI. All of the current process attributes are propagated
; to the subprocess so that it looks like the master process
; context. The subprocess is instructed to wait until we send
; it input. The subprocess is given the other end of our PTY
; as its "terminal".
;
; Calling Sequence:
; CALLS #0,START_SUBPR
;
; Input Parameters: NONE
;
; Output Parameters: NONE
;
; Implicit Inputs:
; PTY_CHAN
;
; Implicit Outputs:
; SUBR_PID, SUBPR_END_STATUS
;
; Procedures called:
; LIB$SPAWN
;
; Completion Status:
; NONE - Errors are signalled.
;
; Side Effects:
;
;--
RWDATA_SECTION
SPAWN_FLAGS:
.LONG 1 ; NOWAIT ! CLISYM ! LOGNAM
PARTNER_DVI_LIST:
REQLIST
ITEM DVI$_UNIT,PARTNER_UNIT_NR,4 ; Request for PTY unit nr.
ITEM DVI$_DEVNAM,PTY_DEVNAME_BUF,PTY_NAME_SZ,-
PTY_DEVNAME ; and device name
REQEND
PARTNER_UNIT_NR:
.BLKL 1 ; Unit nr of PTY control device
PARTNER_DEVNAME_LN:
.BLKW 1 ; Length of partner device name
PARTNER_DEVNAME:
STRING PTY_NAME_SZ ; Local descriptor and buffer
PARTNER_FAO:
.ASCID /_PTY!UW:/ ; FAO string for PTY device name
CODE_SECTION
.ENTRY START_SUBPR,^M
$GETDVI_S -
CHAN=PTY_CHAN,-
ITMLST=PARTNER_DVI_LIST ; Find out unit nr of PTY
SIGNAL_ERROR -
PHOTO_GETDVI ; Check for errors
INCL PARTNER_UNIT_NR ; Partner PTY is n+1
$FAO_S -
CTRSTR=PARTNER_FAO,-
OUTLEN=PARTNER_DEVNAME_LN,-
OUTBUF=PARTNER_DEVNAME,-
P1=PARTNER_UNIT_NR ; Build partner device name
SIGNAL_ERROR -
PHOTO_FAO ; Check for errors
PUSHAL @PARTNER_DEVNAME+4 ; Build descriptor to partner devname
MOVZWL PARTNER_DEVNAME_LN,-
-(SP)
MOVL SP,R2 ; Get address of descriptor
CALL G^LIB$SPAWN -
#0,- ; No command
(R2),- ; Input is the PTY
(R2),- ; Output is the PTY
SPAWN_FLAGS,- ; Option flags
#0,- ; Default process name
SUBPR_PID,- ; Return subprocess PID
SUBPR_END_STATUS,- ; Return subprocess termination status
#0,- ; No completion EFN
SUBPR_END_AST ; Completion AST routine
SIGNAL_ERROR -
PHOTO_SPAWNERR ; Check for errors
RET
.PAGE
.SBTTL CREATE_LOG - Create log file
;++
; Functional Description:
; This routine creates the file specified on the /OUTPUT qualifier.
; After connecting the RAB, it sets the RAB for asynchronous operation.
;
; Calling Sequence:
; CALLS #0,CREATE_LOG
;
; Input Parameters: NONE
;
; Output Parameters: NONE
;
; Implicit Inputs:
; LOG_FAB, LOG_RAB
;
; Implicit Outputs:
; LOG_FAB, LOG_RAB
;
; Procedures called:
; CLI$GET_VALUE, SYS$CREATE, SYS$CONNECT
;
; Completion Status:
; NONE - Errors are signalled
;
; Side Effects: NONE
;
;--
RWDATA_SECTION
LOG_FSPEC:
STRING NAM$C_MAXRSS ; Descriptor and buffer for filespec
LOG_FSPEC_LEN:
.BLKW 1 ; Length of actual filespec
LOG_FILE_QUAL:
.ASCID /OUTPUT/ ; Qualifier name
CODE_SECTION
.ENTRY CREATE_LOG,^M
CALL G^CLI$GET_VALUE LOG_FILE_QUAL,-
LOG_FSPEC ; Get log file qualifier
SIGNAL_ERROR -
PHOTO_PARSERR ; Check for errors
CALL G^STR$TRIM LOG_FSPEC, -
LOG_FSPEC,-
LOG_FSPEC_LEN ; Get length of spec w/o blanks
$FAB_STORE -
FAB=LOG_FAB,-
FNA=@LOG_FSPEC+4,-
FNS=LOG_FSPEC_LEN ; Point FAB at filespec
$CREATE FAB=LOG_FAB ; Create the file
IF THEN
MOVZBL LOG_FSPEC_LEN,R2 ; Get length of filespec
SIGNAL -
CODE1=#PHOTO_LOGOPN,-
F1=,-
CODE2=R0 ; Report an error
ENDIF
$CONNECT RAB=LOG_RAB ; Connect record stream
SIGNAL_ERROR -
PHOTO_LOGCONN ; Check for errors
BISL2 #RAB$M_ASY,-
LOG_RAB+RAB$L_ROP ; Set bit for asynch operation
MOVZWL #1,LOGGING_FLAG ; Flag that logging is enabled
RET
.PAGE
.SBTTL CLEANUP - Cleanup everything
;++
; Functional Description:
; This routine performs all necessary cleanup. All files are closed,
; all channels deassigned, and the subprocess, if it exists, is
; deleted. The terminal characteristics are restored to normal.
; This routine is called as an exit handler as well as directly.
;
; Calling Sequence:
; CALLS #0,CLEANUP
;
; Input Parameters: NONE
;
; Output Parameters: NONE
;
; Implicit Inputs:
; TTY_CHAN, PTY_CHAN, LOG_FAB, LOG_RAB, SUBPR_PID, TTY_OLD_CHAR
;
; Implicit Outputs:
; PTY_CHAN, TTY_CHAN, LOG_FAB, LOG_RAB
;
; Procedures called:
; SYS$CANCEL, SYS$CLOSE, SYS$DELPRC, SYS$DASSGN
;
; Completion Status:
; NONE - No errors are signalled
;
; Side Effects:
; NONE
;
;--
RWDATA_SECTION
CRLF:
.BYTE ^X0D,^X0A ; CRLF
CODE_SECTION
.ENTRY CLEANUP,^M<>
$WAIT -
RAB=LOG_RAB ; Wait for any asynch I/O to finish
$CLOSE -
FAB=LOG_FAB ; Try to close log file
CLRL LOG_RAB+RAB$W_ISI ; and do quick disconnect
$CANCEL_S -
CHAN=TTY_MB_CHAN ; Cancel any I/O on TTY mailbox
$QIOW_S -
CHAN=TTY_CHAN,-
FUNC=#IO$_WRITEVBLK,-
P1=CRLF,-
P2=#2 ; Move cursor to clear of message
$QIOW_S -
CHAN=TTY_CHAN,-
FUNC=#IO$_SETMODE,-
P1=TTY_OLD_CHAR,-
P2=#12 ; Restore old TTY characteristics
$DASSGN_S -
CHAN=TTY_CHAN ; and deassign both channels
$DASSGN_S -
CHAN=TTY_MB_CHAN
$CANCEL_S -
CHAN=PTY_MB_CHAN ; Cancel any I/O on PTY mailbox
$DASSGN_S -
CHAN=PTY_CHAN ; and deassign both channels
$DASSGN_S -
CHAN=PTY_MB_CHAN
tstl SUBPR_PID ; Do not kill if it's 0!!!
beql 10$
$DELPRC_S -
PIDADR=SUBPR_PID ; Try to zap the subprocess
10$:
RET
.PAGE
.SBTTL TTY_DATA_AST - Handle TTY input
;++
; Functional Description:
; This routine is called at AST level when a message is received on
; the associated mailbox. If the message is an "unsolicited data"
; message, reads with zero timeout is done on the TTY to get all
; the data currently in the typeahead buffer. All other mailbox
; messages are ignored.
;
; The data received from the TTY is checked for the toggle character
; which toggles logging. It is then written to the PTY, and
; another associated mailbox read is posted.
;
; Calling Sequence:
; Called as AST routine
;
; Input Parameters:
; Standard AST parameters (none used)
;
; Output Parameters: NONE
;
; Implicit Inputs:
; TTY_CHAN, TTY_IOSB_IN, PTY_CHAN, TTY_RCV_BUFFER
; TTYTA_QIO_LIST, TTY_MB_CHAN, TTY_MB_IOSB, TTY_MB_BUFFER
;
; Implicit Outputs:
; PTY_XMIT_BUFFER, TTY_IOSB_IN, PTYOUT_QIO_LIST
;
; Procedures called:
; POST_TTY_MBREAD, DO_TTY_TA
;
; Completion Status:
; NONE - Errors are signalled.
;
; Side Effects:
;
;--
CODE_SECTION
.ENTRY TTY_DATA_AST,^M
MOVZWL TTY_MB_IOSB,R0 ; Get I/O status for mailbox
IF THEN ; Ignore if called during I/O cancel
SIGNAL_ERROR -
PHOTO_READERR, TTY_DEVNAME ; Signal any errors
; Ignore all but unsolicited data messages
IF THEN
BSBW DO_TTY_TA ; Copy all TTY input to PTY
ENDIF
JSB POST_TTY_MBREAD ; Repost associated mailbox read
ENDIF
RET
.PAGE
.SBTTL PTY_DATA_AST, ^M
;++
; Functional Description:
; This routine is called at AST level when a message is received on
; the mailbox associated with the PTY. If this message specified
; "unsolicited data", reads with zero timeout are made on the PTY to
; obtain all the data in the typeahead buffer. Other mailbox messages
; are ignored.
;
; All data received from the PTY is written to the TTY, and if
; logging is enabled, to the log file. Before this routine
; terminates, it posts another read to the associated mailbox.
; Also, we periodically check for input from the TTY and copy it to
; the PTY. This prevents long PTY output from blocking ^Y's etc.
;
; Calling Sequence:
; Called as AST routine
;
; Input Parameters:
; Standard AST parameters (none used)
;
; Output Parameters: NONE
;
; Implicit Inputs:
; PTY_CHAN, TTY_CHAN, LOGGING_FLAG, PTY_IOSB_IN, PTY_RCV_BUFFER
; PTYTA_QIO_LIST, PTY_MB_CHAN, PTY_MB_IOSB, PTY_MB_BUFFER
;
; Implicit Outputs:
; TTY_XMIT_BUFFER, TTYOUT_QIO_LIST
;
; Procedures called:
; SYS$QIO, LOG_CHARS, POST_PTY_MBREAD, DO_TTY_TA
;
; Completion Status:
; NONE - errors are signalled
;
; Side Effects: NONE
;
;--
TTY_CHECK_FREQ = 3 ; Check tty after three writes
CODE_SECTION
.ENTRY PTY_DATA_AST,^M
; Register usage
; R0-R5 - Scratch
; R6 - TTY write count
MOVZWL PTY_MB_IOSB,R0 ; Get PTY I/O status
ENB_LONG ;; Enable macro long branches
IF THEN ; Ignore if called during I/O cancel
SIGNAL_ERROR -
PHOTO_READERR,PTY_DEVNAME
; Ignore all but unsolicited data messages
IF THEN
CLRL R6 ; Clear TTY write count
$QIOW_G -
PTYTA_QIO_LIST ; Glom data from typeahead buffer
SIGNAL_ERROR -
PHOTO_QIOREAD, PTY_DEVNAME ; Check for QIO error
WHILE OR -
DO
MOVZWL PTY_IOSB_IN,R0 ; Get I/O status
IF THEN ; Timeout is not an error here
SIGNAL_ERROR -
PHOTO_READERR,-
PTY_DEVNAME ; Check for error
ENDIF
ADDW2 PTY_IOSB_IN+6,-
PTY_IOSB_IN+2 ; Compute total data size
MOVZWL PTY_IOSB_IN+2,R2 ; Get character count
MOVAL PTY_RCV_BUFFER,R3 ; and address
JSB LOG_CHARS ; And log them
MOVC3 PTY_IOSB_IN+2,-
PTY_RCV_BUFFER,-
TTY_XMIT_BUFFER ; Move the data
MOVZWL PTY_IOSB_IN+2,-
TTYOUT_QIO_LIST+QIO$_P2 ; Setup QIO parameter
$QIOW_G TTYOUT_QIO_LIST ; Write data to TTY
SIGNAL_ERROR -
PHOTO_QIOWRITE,TTY_DEVNAME ; Check for error
INCL R6 ; Increment count
IF THEN
BSBW DO_TTY_TA ; Time to check terminal
CLRL R6 ; Reset count
ENDIF
$QIOW_G -
PTYTA_QIO_LIST ; Glom data from typeahead buffer
SIGNAL_ERROR -
PHOTO_QIOREAD, PTY_DEVNAME ; Check for QIO error
ENDWHILE
ENDIF
JSB POST_PTY_MBREAD ; Hang another read on PTY
ENDIF
DSB_LONG ;; Disable macro long branches
RET
.PAGE
.SBTTL SUBPR_END_AST - AST for subprocess termination
;++
; Functional Description:
; This routine is called at AST level when our subprocess terminates.
; Wake the main process to perform cleanup.
;
; Calling Sequence:
; Called as AST routine
;
; Input Parameters:
; Standard AST parameters (none used)
;
; Output Parameters: NONE
;
; Implicit Inputs:
; SUBPR_END_STATUS
;
; Implicit Outputs: NONE
;
; Procedures called:
; SYS$WAKE
;
; Completion Status:
; NONE - errors are signalled
;
; Side Effects: NONE
;
;--
CODE_SECTION
.ENTRY SUBPR_END_AST,^M<>
$WAKE_S ; Wake up mainline code
RET
.PAGE
.SBTTL AST helper routines
;++
; Functional Description:
; These routines are called primarily by the AST level routines to
; perform miscellaneous tasks.
;
; Calling Sequence:
; All JSB entry points
;
; Input Parameters: NONE
;
; Output Parameters: NONE
;
; Implicit Inputs:
; Various
;
; Implicit Outputs:
; Various
;
; Procedures called:
; SYS$QIO, SYS$WAIT
;
; Completion Status:
; NONE - errors are signalled
;
; Side Effects: NONE
;
;--
CODE_SECTION
;+
; Following routines are used to queue reads on the device associated mailboxes
;-
POST_PTY_MBREAD::
$QIO_G PTYMB_QIO_LIST ; Queue the read
SIGNAL_ERROR -
PHOTO_QIOMB,PTY_DEVNAME ; Check for error
RSB
POST_TTY_MBREAD::
$QIO_G TTYMB_QIO_LIST ; Queue the read
SIGNAL_ERROR -
PHOTO_QIOMB,TTY_DEVNAME ; Check for error
RSB
;+
; This routine is called from the two data AST routines to copy all
; available TTY data to the PTY.
;-
DO_TTY_TA::
ENB_LONG ;; Enable long branches for macros
$QIOW_G -
TTYTA_QIO_LIST ; Glom up typeahead contents
SIGNAL_ERROR -
PHOTO_QIOREAD, TTY_DEVNAME ; Check for QIO error
WHILE OR -
DO
MOVZWL TTY_IOSB_IN,R0 ; Get I/O status
IF THEN ; Timeout is not an error
SIGNAL_ERROR -
PHOTO_READERR,-
TTY_DEVNAME ; Signal any other errors
ENDIF
ADDW2 TTY_IOSB_IN+6,-
TTY_IOSB_IN+2 ; Get total length of data
JSB CHECK_TOGGLE ; Check for toggle character
MOVC3 TTY_IOSB_IN+2,-
TTY_RCV_BUFFER,-
PTY_XMIT_BUFFER ; Move the data
MOVZWL TTY_IOSB_IN+2,-
PTYOUT_QIO_LIST+QIO$_P2 ; Set QIO list for this
; transfer
$QIOW_G -
PTYOUT_QIO_LIST ; and write the data
SIGNAL_ERROR -
PHOTO_QIOWRITE,PTY_DEVNAME ; Check for errors
$QIOW_G -
TTYTA_QIO_LIST ; Glom up typeahead contents
SIGNAL_ERROR -
PHOTO_QIOREAD, TTY_DEVNAME ; Check for QIO error
ENDWHILE
RSB
DSB_LONG ; Disable long branches for macros
;+
; Following routine checks the current contents of the TTY receive buffer
; for the logging toggle character
;-
CHECK_TOGGLE::
LOCC TOGGLE_CHAR,-
TTY_IOSB_IN+2,-
TTY_RCV_BUFFER ; Look for the character
IF THEN
XORL #^X1,LOGGING_FLAG ; Toggle the flag
IF THEN ; Issue informative message
SIGNAL -
CODE1=#PHOTO_TOGON,-
F1=#0 ; We turned it on
ELSE
SIGNAL -
CODE1=#PHOTO_TOGOFF,-
F1=#0 ; We turned if off
ENDIF
ENDIF
RSB
;+
; Following routine handles the logging of characters to the log file.
; R0-R1 - Scratch. Modified.
; R2 - Number of characters to store. Modified.
; R3 - Address of characters. Modified.
; R8-R9 - Scratch. Modified.
;-
LOG_CHARS::
ENB_LONG ; Enable long branch macros
IF THEN ; If we are logging now
MOVL LINE_NEXTCH,R8 ; Get pointer and count for buffer
MOVL LINE_COUNT,R9
WHILE DO
IF AND -
THEN
INCL R3 ; Skip CR at beginning of line
DECL R2 ; so time stamps look right
ELSE
MOVB (R3),(R8) ; Buffer the character
INCL R3 ; Adjust pointers
INCL R8
DECL R2 ; And adjust counts
INCL R9
IF OR -
THEN
; Buffer is full, or an LF was found. Write the record with optional
; time stamp.
MOVAL LINE_BUFFER,R8 ; Point to start of buffer
IF THEN
$ASCTIM_S -
TIMBUF=STAMP_DESC,-
CVTFLG=#1 ; Get the time
SIGNAL_ERROR -
PHOTO_GETTIM,R0 ; Check for error
ADDL2 #STAMP_SZ,R9 ; And compute record length
MOVAL STAMP_TIME,R8 ; And get buffer address
ENDIF
$WAIT -
RAB=LOG_RAB ; Wait for any previous activity
$RAB_STORE -
RAB=LOG_RAB,-
RBF=(R8),-
RSZ=R9 ; Point RAB at record
$PUT -
RAB=LOG_RAB ; Write the record
SIGNAL_ERROR -
PHOTO_LOGIO,R0 ; Check for error
MOVAL LINE_BUFFER,R8 ; Reset pointer
CLRL R9 ; and count
ENDIF
ENDIF
ENDWHILE
MOVL R8,LINE_NEXTCH ; Save buffer info
MOVL R9,LINE_COUNT
ENDIF
DSB_LONG ; Disable long branch macros
RSB
.END PHOTO