.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