.TITLE BATCH SINGLE STREAM BATCH .IDENT /V02/ ; ; VERSION V01.00 ; ; ERIC ROSDOL SWS/VIENA ; ; 11-FEB-78 ; ; MODULE CONTENTS: ; ; BATCH FOR RSX11M, IS A SINGLE STREAM BATCH PROCESS WHICH USES A ; TWO UNIT VIRTUAL TERMINAL (NOT THE M-PLUS VERSION). IT REQUIRES THE ; SPAWN COMMAND FOR SUBMITTING COMMANDS TO THE VIRTUAL TERMINAL. ; ; MODULE MODIFICATION HISTORY: ; ; VERSION V02: 27-JUL-80 ; ; JAMES G. DOWNWARD ; KMS FUSION ; 3941 RESEARCH PARK DR ; ANN ARBOR, MICH. 48106 ; (313)-769-8500 ; ; A MAJOR(!!) rewrite. With the advent of the V3.2 SPAWN command ; a more elegant and less confusing way of talking with the virtual ; terminal VT0: and maintaining syncronization without elaborate kludges ; became available. All the past horrors required to maintain syncronization ; with MCR have been cleaned up. BATCH now requires the use of the SPAWN ; command. In addition, all previous bug fixes and enhancements have ; been retained(file truncation, logging long lines). Batch now uses PIN ; to execute the commands on VT0: (but the intrepid user could easily ; convert it to user ...AT. instead). ; ; ; MACRO CALL DEFINITIONS ; .MCALL ALUN$C,QIOW$,MRKT$C,RCVX$C,EXIT$S,FDAT$A,OPEN$W,GET$ .MCALL CMKT$S,GLUN$C,DIR$,QIOW$C,ASTX$S,QIO$,CLOSE$,OPEN$R,PUT$ .MCALL FDBDF$,FDRC$A,FDOP$A,FSRSZ$,FINIT$,PRINT$,DELET$,OPEN$U .MCALL GTSK$C,UCBDF$,WTSE$,ENCP$S,DSCP$S,SPWN$ .MCALL QIOW$ UCBDF$ ;DEBUG=0 ; ; LOCAL MACRO DEFINITIONS ; ; SAVE A REGISTER ON THE STACK .MACRO PUSH X MOV X,-(SP) .ENDM ; RECALL A REGISTER FROM OFF OF THE STACK .MACRO POP X MOV (SP)+,X .ENDM ; PRINT AN ASCIZ STRING .MACRO PRINT STRING PUSH R0 PUSH R1 MOV #STRING,R0 CALL PNTLIN POP R1 POP R0 .ENDM PRINT .NLIST BEX ; ; EQUATED SYMBOLS ; ; ; FILE DEFINITION BLOCKS ; LOG: FDBDF$ FDAT$A R.VAR,FD.CR ; FDRC$A ,LOGBUF,132. ; EXPAND TO 132 CHARS. FDOP$A 1,LOGDS,,FO.WRT ; ; FILE STORAGE REGION ; FSRSZ$ 1 ; ONLY ONE FILE AT A TIME ; ; DATA SET DESCRIPTOR BLOCK FOR THE LOG-FILE ; LOGDS: .WORD DEVL,DEV .WORD 0,0 ; UFD DESCRIPTOR BLOCK =0 => USE DEFAULT ; UIC DESCRIPTOR IN $$FSR2 .WORD 0,FILNM ; WILL BE DEFINED AT RUN TIME ; DEVICE FOR LOG FILES. ; IT IS A PECULIARITY OF TASKS INSTALLED AS SLAVE THAT THEY DO NOT KNOW ; THE SY: OF THE TASK STARTING THEM OFF. WHEN AN ALUN$ ; IS DONE, ONLY THE GLOBAL ASSIGNMENTS ARE SEARCHED, NOT THOSE LOCAL ; TO THE INITIATING TERMINAL(WHICH BATCH KNOWS ABOUT). THIS CAUSES A ; PROBLEM SINCE THE LOG FILE MUST BE WRITTEN OUT TO THE DISK DRIVE ; CORRESPONDING TO THE SY: OF THE USER SUBMITTING THE FILE. EVEN ; SWITCHING TO SYSTEM STATE AND SCANNING THE LOGICAL ASSINGMENTS ; TABLE FOR THE TERMINAL WILL NOT HANDLE ALL PATHALOGICAL CASES. ; (WHAT IF USER LOGS OFF, BATCH KNOWS TI:, BUT WHERE'S SY:?). ONE WAY ; AROUND THE PROBLEM IS TO CODE THE COMMAND TO BATCH(FROM SUBMIT) IN ; RAD50 FORMAT WHICH WOULD LEAVE ROOM FOR SENDING THE BATCH SY0:(WHICH ; BY THE WAY SUBMIT WOULD HAVE TO FIND) ON TO WHICH TO WRITE THE LOG ; FILES. ; AS A TEMPORARY EXPEDIENT, ALL USERS WHO WILL BE USING BATCH, ARE NOW ; AND WILL REMAIN ON LB1:( GLOBALLY ASSIGNED, IN OUR CASE TO DM:) DEV:: .ASCII /DM0:/ ; THIS MUST BE HARDWIRED IN UIC: .ASCIZ /[000,000]/ ; WILL BE USED IN CREATING THE DEFAULT UIC ; DISCRIPTOR IN $$FSR2 DEVL=4 UICL=9. .EVEN LOGXT: .ASCII /.LOG;1/ ; ONLY EVER KEEP ONE VERSION OF A LOG FILE BYEBUF: .ASCII /BYE/<15> BYECT=.-BYEBUF ; ; DIRECTIVE PARAMETER BLOCKS ; ;VT1WRT: QIO$ IO.WLB,5,5,,,,<0,0,0> VT1RD: QIOW$ IO.RLB,5,5,,VTSTAT,,; UP TO 132 CHARS BACK SPNDPB: SPWN$ MCR...,,,,,1,SPNAST,EXSTAT,,,0,VT QIODPB: QIOW$ IO.WVB,6,6,,,,<0,0,40> ; WRITE TO TERMINAL ; ; LOCAL DATA ; VTSTAT: .BLKW 2 ; LUNINF: .BLKW 6 ; LUN INFORMATION GLNBUF: .BLKW 6 ; BUFFER FOR GETLUN CMDBUF: .BLKW 2 ; SENDERS TASK NAME RAD50 SPEC: .BLKW 15. ; SPECIFIER BUFFER AND OVERHEAD LOGBUF: .BLKW 140. ; BUFFER FOR LOGFILE RECORD FILNM: .BLKW 30. ; LOGFILE FILENAME SNDNAM: .BLKW 2 ; SENDER'S TASK NAME TEMP: .WORD 0 ; TEMP STORAGE COUNT: .WORD 0 ; CHARACTER COUNT TSKBUF: .BLKW 16. ; BUFFER FOR GTSK$ DIRECTIVE EXSTAT: .BLKW 8. ; EXIT STATUS BLOCK PNSTAT: .WORD 0 ; EXIT STATUS OF PIN ISDONE: .WORD 0 ; =0 SPAWN NOT DONE, =1, SPAWN DONE ; ; LOCAL MESSAGES ; .ENABL LC MSG1: .ASCIZ <15>/BAT -- Job completed SUCCESFULLY/<15><12><7>/>/ MSG2: .ASCIZ <15>"BAT -- I/O ERROR ON LOG FILE "<7><7><15><12>/>/ MSG3: .ASCIZ <15>/BAT -- ATTACH FAILURE ON VT:/<7><7><15><12>/>/ MSG4: .ASCIZ <15>/BAT -- NOT ABLE TO LOG ONTO VT, TRY AGAIN/<7><15><12>/>/ MSG5: .ASCIZ <15>/BAT -- COMMAND FILE EXTENSIONS NOT ALLOWED/<7><15><12>/>/ MSG6: .ASCIZ <15>/BAT -- SPAWN OF PIN TO VT FAILED/<7><15><12>/>/ MSG7: .ASCIZ <15>/BAT -- Job stream exited with ERROR/<7><15><12>/>/ MSG8: .ASCIZ <15>/BAT -- Job stream exited with SEVERE ERROR/<7><15><12>/>/ .EVEN HDRTXT: .ASCII /** START OF COMMAND FILE SUBMITTED BY :/ TSKNAM: .BLKB 6. .ASCII / **/ HDRLN=.-HDRTXT .EVEN ;+ ; ; This routine tries to get a data packet out of its receive queue. ; If this queue is empty, it simply exits. If not, command logon ; information is parsed and HELLO spawned to VT0:. After logging in, the ; procedure file is submitted to VT0: for execution. Note that the ; virtual terminal is not used to submit MCR type commands from an ; unprivleged task. It is used to get command file information logged ; under a file rather than on the normal TI: terminal (which in addition ; it ties up). ; ; Batch must be installed as a slave task. If it is slave it assumes the ; UIC of the sender task(...SUB) and the TI: of the sender task. ; both features are necessary if batch is to open a file on the user's ; UFD and notify the user (on his very own TI:) when all is done. ; this requires that batch be privleged because it must be able to write ; into any UIC requested by SUB. Also it must be privleged to continue ; execution if user logs off his terminal.(BATCH must never be aborted). ; .ENABLE LSB BATCH:: ; REFERENCE LABEL ENCP$S ; ENABLE CHECKPOINTING, IF DISABLED RCVX$C ,CMDBUF ; GET FIRST PACKET (COMMAND) CALL SETFSR ; SET UP CORRECT UIC IN $FSR2 ALUN$C 6,TI,0 ; ASSIGN TI OF SENDER TASK ALUN$C 4,VT,0 ; ASSIGN TO VT AND CHECK IF LOADED BCS 15$ ; IF CS DEVICE NOT LOADED, PRINT ERROR MSG 10$: ALUN$C 5,VT,1 ; ASSIGN TO COMMAND INPUT QIOW$C IO.ATT,5,5 ; ATTACH VT1 TERMINAL BCC 20$ ; IF CC ATTACH OK 15$: JMP ATTERR ; OTHERWISE PRINT ERROR 20$: MOV #CMDBUF,R1 ; GET ADDRESS OF SPEC'S MOV (R1),SNDNAM ; SAVE TASK NAME MOV 2(R1),SNDNAM+2 ; OF SENDER TASK MOV (PC)+,(R1)+ ; STORE THE LOGGON .ASCII /HE/ MOV (PC)+,(R1)+ ; COMMAND FOR VT1 .ASCII /L / 30$: CMPB #' ,(R1)+ ; SCAN RECEIVE BUFFER FOR BLANK AFTER PASWORD BNE 30$ ; IF NE NO, CHECK AGAIN MOVB #15,-1(R1) ; STUFF IN A AFTER LOGIN PASSWORD MOV R1,R2 ; COPY START OF CMD FILE NAME FOR LATER USE SUB #CMDBUF,R1 ; GET LENGTH OF STRING MOV R1,SPNDPB+S.PWCL; SET LENGTH OF HELLO COMMAND MOV #CMDBUF,SPNDPB+S.PWCA ; SET ADDRESS OF COMMAND LINE MOV #FILNM,R3 ; SET ADDRESS OF FILENAME BUFFER 40$: MOVB (R2)+,(R3) ; COPY THE IND-FILENAME CMPB #'.,(R3) ; IS THE USER TRYING TO INCLUDE AN EXTENSION BNE 45$ ; NOT THIS TIME ANYWAY PRINT MSG5 ; WARN USER OF PROBLEM JMP BATCH ; AND LOOK TO SEE IF ANOTHER FILE TO PROCESS 45$: TSTB (R3)+ ; HAVE WE GOTTEN TO THE END(NULL BYTE) BNE 40$ ; IF NE, NOT FINISHED MOV #LOGXT,R4 ; SET ADDRESS OF EXTENSION DEC R3 ; OVERWRITE THE NULL BYTE .REPT 6 ; DO IT OVER 6 TIMES, IT'S EASIER MOVB (R4)+,(R3)+ ; APPEND EXTENSION AND VERSION .ENDR MOVB #15,-1(R2) ; TERMINATE LINE WITH SUB #FILNM,R3 ; FILE NAME LENGTH MOV R3,LOGDS+10 ; SETUP INDSDB OPEN$W #LOG ; OPEN OUTPUT FILE BCC 50$ ; IF CC NO FILE ERROR JMP FILERR ; OPEN ERROR 50$: PUSH R0 ; SAVE IT, BECAUSE NEXT PUSH R1 ; ROUTINE NEEDS IF MOV #TSKNAM,R0 ; GET ADDRESS TO STORE MOV SNDNAM,R1 ; GET FIRST RAD50 HALF OF TASK NAME CALL $C5TA ; CONVERT TO ASCII STRING MOV SNDNAM+2,R1 ; GET SECOND RAD50 HALF OF TASK NAME CALL $C5TA ; CONVERT TO ASCII STRING POP R1 ; GET OLD REGISTERS POP R0 ; BACK FROM STACK PUT$ R0,#HDRTXT,#HDRLN ; WRITE LOG HEADER BCC 60$ ; IF CC PUT OK JMP FILERR ; OTHERWISE FILE ERROR 60$: ;PUT$ R0,#CMDBUF,R1 ; LOG THE HELLO INPUT BCC 70$ ; IF CC OK JMP FILERR ; OTHERWISE FILE ERROR 70$: CALL SBMCMD ; ISSUE HELLO COMMAND CMP EXSTAT,#1 ; WAS LOGIN SUCCESSFUL BEQ 75$ ; IF EQ, YES PROCEED CLOSE$ R0 ; CLOSE THE LOG FILE PRINT MSG4 ; WARN USER THAT HE COULDN'T LOG ONTO VT: QIOW$C IO.KIL,5,5 ; TIDY UP ANY LEFT OVER I/O JMP BATCH ; GET A NEW COMMAND LINE 75$: ; SUB #2,R3 ; NOW FILENAME WITHOUT EXT., WITH AND PIN MOV R3,SPNDPB+S.PWCL; INSERT LENGTH INTO SPWN DPB SUB #4,R1 ; MOVE BACK SO CAN INSERT PIN MOV #CMDBUF,SPNDPB+S.PWCA ; INSERT ADDRESS OF CMD BUFFER ADD R1,SPNDPB+S.PWCA; POINT DPB TO START OF CMD FILE MOV SPNDPB+S.PWCA,R1; BFR ADR 4 CHAR IN FRONT OF FILE NAME MOVB #'P,(R1)+ ; INSERT A 'P' MOVB #'I,(R1)+ ; INSERT A 'I' MOVB #'N,(R1)+ ; INSERT A 'N' MOVB #' ,(R1) ; INSERT A CLR ISDONE ; CLEAR FLAG TO INDICATE SPAWN DONE DIR$ #SPNDPB ; SPAWN COMMAND TO MCR... BCC 80$ ; PRINT MSG6 ; SPAWN TO VT FAILED JMP 100$ ; LOG OFF 80$: ; REFERENCE LABLE TST ISDONE ; IS SPAWN COMPLETED BNE 100$ ; IF NE, YES, GO ISSUE BYE COMMAND CALL READVT ; CONTINUE TO ISSUE READS TO VT: BCS 80$ ; RE-READ CMP VTSTAT+2,#4 ; IF COUNT OF 4 ->A '>' ONLY BEQ 80$ ; IF SO DON'T OUTPUT RECORD PUT$ R0,TEMP,VTSTAT+2; LOG THE MCR OUTPUT BCC 80$ ; IF CC NO FILE ERROR JMP FILERR ; OTHERWISE PRINT ERROR 100$: ; REF LABLE MOV EXSTAT,PNSTAT ; COPY EXIT STATUS OF PIN MOV #BYEBUF,SPNDPB+S.PWCA ; SETUP ADDRESS OF BYE COMMAND MOV #BYECT,SPNDPB+S.PWCL ; SET UP BYTE COUNT OF COMMAND CALL SBMCMD ; ISSUE BYE COMMAND .ENABL LSB RESUM: ;PRINT$ R0 ; SPOOL THE LOG FILE CLR R1 ; TO REWIND A FILE TO START SET R1=0,R3=0 AND CLR R3 ; SET R2=1(FIRST BLOCK). WE MUST REWIND MOV #1,R2 ; FILE TO START ELSE .TRNCL WILL NOT WORK CALL .POINT ; REWIND THE FILE AND THEN CALL .TRNCL ; CLOSE THE FILE AND TRUNCATE IT BCS FLERR ; IF CS, TRUNCATE ERROR CMP PNSTAT,#1 ; DID COMMAND FILE EXIT SUCCESSFULLY BNE 10$ ; NO, SOME ERROR OCCURED PRINT MSG1 ; YES,PRINT READY MESSAGE BR 50$ ; JOIN COMMON CODE 10$: CMP PNSTAT,#4 ; DID COMMAND FILE EXIT WITH SEVERE ERROR BNE 20$ ; NO, SOME OTHER KIND OF(WARNING?) ERROR PRINT MSG8 ; WARN OF SEVERE ERROR BR 50$ ; AND CONTINUE 20$: PRINT MSG7 ; MUST BE WARNING ERROR 50$: QIOW$C IO.KIL,5,5 ; KILL ANY PENDING IO JMP BATCH ; DEQUE NEXT REQUEST OR EXIT FLERR: JMP FILERR ; GO REPORT FILE ERROR .DSABLE LSB ;+ ; READVT ; ISSUE A READ TO THE VT: ; REMOVE GARBAGE '>', '+' FROM THE BUFFER PRIOR TO PRINTING ; CC - SET, DON'T OUTPUT A RECORD ON RETURN TO MAINLINE ; CC - CLEAR, OUTPUT A RECORD ON RETURN TO MAINLINE ; ;- READVT: DSCP$S ; DISABLE CHECKPOINTING WHILE TALKING TO VT: ; BECAUSE BATCH AND ALL VT TASKS GET LOCKED ; UP IF BATCH GETS CHECKPOINTED DIR$ #VT1RD ; READ MCR MESSAGES ENCP$S ; MAKE TASK CHECKPOINTABLE AGAIN CMP VTSTAT+2,#4 ; IF COUNT OF 4 ->A '>' ONLY BEQ 60$ ; IF SO DON'T OUTPUT RECORD MOV #LOGBUF,TEMP ; GET START OF BUFFER PUSH R5 ; SAVE R5 MOV VTSTAT+2,R5 ; GET CHARACTER COUNT ADD TEMP,R5 ; POINT TO END OF BUFFER CMPB (R5),#'> ; IS IT A '>' BNE 10$ ; NO ,SKIP AROUND CLRB (R5) ; YES, MAKE IT A NUL 10$: CMPB (R5),#12 ; IS IT A LF BNE 20$ ; NO, SKIP CLRB (R5) ; YES, MAKE IT A NULL 20$: POP R5 ; RESTORE R5 CMPB #'+,@TEMP ; MAYBE WE HAVE A '+' BNE 30$ ; IF NE, NO INC TEMP ; YES, SKIP OVER DEC VTSTAT+2 ; AND DECREASE CHARACTER COUNT 30$: ; REF LABLE PUSH R5 ; SAVE R5 CMPB #'>,(R5) ; MAYBE SECOND CHARACTER IS A '>' BNE 40$ ; IF NE, NO SKIP AROUND CLRB (R5) ; YES SO MAKE IT A NUL 40$: ; REF LABLE POP R5 ; RESTORE R5 CLC ; OUTPUT A RECORD RETURN ; BACK TO MAINLINE 60$: SEC ; DON'T OUTPUT TO FILE RETURN ;+ ; **-SBMCMD ; ; THIS ROUTINE SPAWNS THE PREPARED COMMANDLINE ; TO VT0: (EITHER HELLO OR BYE) AND READS THE ; MCR OUTPUTS AND PUTS IT IN THE LOG FILE. ; ; INPUTS: ; ; R0=ADDRESS OF LOG FDB ; DPB'S=PREPARED TO ISSUE COMMAND ; LOGFILE ALREADY OPEN ; ; OUTPUTS: ; ; R0=UNCHANGED ; REQUESTED PROCEDURE DONE (HEL, BYE) ; DIRECT JUMP TO FILERR IF FILE ERROR ; ;- .ENABLE LSB SBMCMD: CLR ISDONE ; SHOW SPAWNED TASK NOT DONE DIR$ #SPNDPB ; SPAWN THE HELLO/BYE COMMAND 10$: DIR$ #VT1RD ; READ MCR OUTPUT .IF DF DEBUG PUT$ R0,#LOGBUF,VTSTAT+2 ; LOG THE MCR OUTPUT .ENDC BCS 40$ ; IF CS FILE ERROR TST ISDONE ; IS SPAWN COMPLETE BEQ 10$ ; NO, READ AGAIN 35$: RETURN ; SO GO RETURN TO CALLER 40$: TST (SP)+ ; FILE I/O ERROR, REMOVE ARG FROM STACK JMP FILERR ; AND LEAVE ROUTINE DIRECTLY .ENABLE LSB ;+ ; SPNAST ; ; AST SERVICE ROUTINE TO OCCUR IF A SPAWNED COMMAND ; IS COMPLETED. THE FLAG ISDONE IS SET TO TELL ALL ; WE CAN STOP READING. ;- SPNAST: TST (SP)+ ; REMOVE EVENT FLAG FROM STACK MOV #1,ISDONE ; SET COMMAND DONE INDICATOR ; MOV #STOPIT,2(SP) ; HAVE IT STOP READING AND RETURN HERE QIOW$C IO.KILL,5,5 ; TIDY UP ANY LEFT OVER I/O ASTX$S ; EXIT AST ROUTINE ;+ ; **-FILERR ; **-ATTERR ; ; SOME SORT OF INTELLIGENT ERROR HANDLING SHOULD ; BE DONE THERE, HOWEVER: ; ENTRY AT FILERR >> PRINT ERROR AND START OVER ; ENTRY AT ATTERR >> PRINT ERROR AND EXIT ( NO VT AVAILABLE) ; ;- FILERR: MOV F.ERR(R0),LOGBUF ; PRESERV FILE SYSTEM ERROR CLOSE$ R0 ; CLOSE THE LOG FILE MOV #MSG2+31.,R0 ; ADDR OF WHERE ERROR CODE GOES MOV LOGBUF,R1 ; ERROR CODE BIS #177400,R1 ; TURN ON HI ORDER BITS(TO CONVERT CORRECTLY) CLR R2 ; SUPRESS LEADING ZEROS CALL $CBDSG ; CONVERT BINARY ERROR CODE TO SIGNED DECIMAL PRINT MSG2 ; PRINT THE ERROR MESSAGE PRINT DEV ; PRINT OUT DEVICE ; PRINT UIC ; AND UIC JMP BATCH ; START OVER AGAIN ATTERR: ; REFERENCE LABEL PRINT MSG3 ; PRINT ERROR MESSAGE EXIT$S ; AND LEAVE PROGRAM ;+ ; SETFSR ; ; Note, it is necessary to insert the task's UIC into $$FSR2. Since BAT... ; is a slave task,'s UIC becomes that of the initiating terminal. When it ; initiated, the act of first starting BATCH up, correctly initializes the ; default directory string in $$FSR2. However, if BATCH receives another ; request before exiting, the default UIC in $$FSR2 must be changed to ; that of the new terminal's UIC. ;- SETFSR: ; THE TASK HAS NOW HAS THE TI: AND UIC ; OF ...SUB. HOWEVER IT IS NECESSARY TO ; PUT THE INFORMATION ON UIC INTO $$FSR2 TO ; GOVERN UIC BATCH TRIES TO OPEN A LOG FILE ON GTSK$C TSKBUF ; GET PARMS OF THIS TASK(LIKE UIC OF TI:) MOV #TSKBUF+30.,R0 ; ADDRESS OF UIC WORD MOV (R0),R3 ; BINARY REPRESENTATION OF UIC MOV #UIC,R2 ; WHERE UIC STRING WILL GO MOV #1,R4 ; DO NOT SUPPRESS LEADING ZEROS CALL .PPASC ; CONVERT BINARY UIC TO ASCII MOV #UIC,R2 ; CREATE DEFAULT DIRECTORY STRING IN $$FSR2 MOV #9.,R1 ; 9 BYTES LONG CALL .WDFDR ; WRITE IT INTO $$FSR2 RETURN ; ;+ ; PNTLIN ; ; THIS ROUTINE WILL PRINT AN ASCIZ LINE ;- PNTLIN: MOV #-1,R1 ; GET COUNT INITIALIZED MOV R0,QIODPB+Q.IOPL ; STORE BUFFER ADDRESS 10$: INC R1 ; INCREMENT COUNTER TSTB (R0)+ ; IS THIS THE LAST BYTE? BNE 10$ ; NO. KEEP GOING MOV R1,QIODPB+Q.IOPL+2 ; STORE BYTE COUNT DIR$ #QIODPB RETURN .END BATCH