Google
 

Trailing-Edge - PDP-10 Archives - bb-m780d-sm - monitor-sources/clufrk.mac
There are 13 other files named clufrk.mac in the archive. Click here to see a list.
; UPD ID= 8492, RIP:<7.MONITOR>CLUFRK.MAC.14,   9-Feb-88 12:18:13 by GSCOTT
;TCO 7.1218 - Insert copyright notice.
; UPD ID= 8388, RIP:<7.MONITOR>CLUFRK.MAC.13,  27-Jan-88 10:30:23 by GSCOTT
;TCO 7.1200 - GETRTL is now in XCDSEC.
; UPD ID= 289, RIP:<7.MONITOR>CLUFRK.MAC.12,  12-Nov-87 15:13:49 by RASPUZZI
;Fix up previous edit. I used an old source for comparison and didn't
;use REDIT to merge the changes in.
; UPD ID= 288, RIP:<7.MONITOR>CLUFRK.MAC.11,  12-Nov-87 15:10:26 by RASPUZZI
;TCO 7.1132 - Bind CLUDGR fork in queue 1 and see how much more the response
;             is for cluster SYSTAT. also, set JP%SYS for the CLUDGR fork.
;             This is an experiment and maybe changed again later.
; UPD ID= 287, RIP:<7.MONITOR>CLUFRK.MAC.10,  11-Nov-87 14:23:05 by RASPUZZI
;Restore a line that was incidentally removed.
; UPD ID= 242, RIP:<7.MONITOR>CLUFRK.MAC.9,   4-Nov-87 16:29:20 by RASPUZZI
;TCO 7.1114 - Prevent ILMNRFs and KLPHOGs on remote system by making sure
;             CLFLNS calculates the send word value correctly
; UPD ID= 233, RIP:<7.MONITOR>CLUFRK.MAC.8,  29-Oct-87 16:21:52 by RASPUZZI
;TCO 7.1105 - Now do TCO 7.1087 right since we are sober.
;TCO 7.1104 - Make CLFMTO execute the MTOPR% JSYS in section 0.
; UPD ID= 230, RIP:<7.MONITOR>CLUFRK.MAC.7,  28-Oct-87 19:01:10 by RASPUZZI
;Add the missing portions of TCO 7.1090 that I didn't put in.
; UPD ID= 225, RIP:<7.MONITOR>CLUFRK.MAC.6,  28-Oct-87 14:16:43 by RASPUZZI
;TCO 7.1094 - Make CLFMSR find structure name in correct location when
;             performing remote MSTR function .MSGSS.
; UPD ID= 222, RIP:<7.MONITOR>CLUFRK.MAC.5,  28-Oct-87 10:27:13 by RASPUZZI
;TCO 7.1090 - ***PERFORMANCE*** Only send over the exact number of words
;             across the CI to remote system. Also, calls to routine
;             FILLIN have to change.
; UPD ID= 218, RIP:<7.MONITOR>CLUFRK.MAC.4,  27-Oct-87 15:57:23 by RASPUZZI
;TCO 7.1087 - Return class scheduling information for .INSYS function
;             for remote INFO% request.
; UPD ID= 196, RIP:<7.MONITOR>CLUFRK.MAC.3,  22-Oct-87 14:46:54 by RASPUZZI
;More of TCO 7.1076 - Make CLFSYS use the local job number when obtaining
;                     logged in directory out of JOBDIR
; UPD ID= 188, RIP:<7.MONITOR>CLUFRK.MAC.2,  21-Oct-87 17:32:16 by RASPUZZI
;TCO 7.1076 - Add CLUDGR SYSYAP. This contains the CLUDGR fork's
;             supporting routines.

;	COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1988.
;	ALL RIGHTS RESERVED.
;
;	THIS SOFTWARE IS FURNISHED UNDER A  LICENSE AND MAY BE USED AND  COPIED
;	ONLY IN  ACCORDANCE  WITH  THE  TERMS OF  SUCH  LICENSE  AND  WITH  THE
;	INCLUSION OF THE ABOVE  COPYRIGHT NOTICE.  THIS  SOFTWARE OR ANY  OTHER
;	COPIES THEREOF MAY NOT BE PROVIDED  OR OTHERWISE MADE AVAILABLE TO  ANY
;	OTHER PERSON.  NO  TITLE TO  AND OWNERSHIP  OF THE  SOFTWARE IS  HEREBY
;	TRANSFERRED.
;
;	THE INFORMATION IN THIS  SOFTWARE IS SUBJECT  TO CHANGE WITHOUT  NOTICE
;	AND SHOULD  NOT  BE CONSTRUED  AS  A COMMITMENT  BY  DIGITAL  EQUIPMENT
;	CORPORATION.
;
;	DIGITAL ASSUMES NO  RESPONSIBILITY FOR  THE USE OR  RELIABILITY OF  ITS
;	SOFTWARE ON EQUIPMENT THAT IS NOT SUPPLIED BY DIGITAL.
	SEARCH CLUPAR,PROLOG,SCAPAR,TTYDEF
	EXTERN MTOLEN,MUTLEN,SKDLEN,HSTSIZ
	SALL

	TTITLE (CLUFRK,,< - Supporting routines for the CLUDGR fork>)
;	M. Raspuzzi October 87

;CLUFRK - Routines that make CLUDGR's fork perform.
	Subttl	Table of Contents

;		     Table of Contents for CLUFRK
;
;				  Section		      Page
;
;
;    1. CLUDGR Fork
;        1.1    Data Storage . . . . . . . . . . . . . . . . .   4
;        1.2    CLSFRK (Start the CLUDGR fork) . . . . . . . .   5
;        1.3    CLFTAB (Dispatch table for CLUDGR fork)  . . .   6
;        1.4    CLFRUN (Begin running CLUDGR fork here)  . . .   7
;        1.5    CLFDED (Dead entry in CLREQQ)  . . . . . . . .   9
;        1.6    CLFALL (All buffers for a request are in)  . .  10
;        1.7    CLFDST (Do DIRST for remote system)  . . . . .  11
;        1.8    CLFGTB (Do GETAB% simulation)  . . . . . . . .  12
;        1.9    CLFGTY (Do GTTYP% simulation)  . . . . . . . .  13
;        1.10   CLFINL (Simulate INLNM% JSYS)  . . . . . . . .  14
;        1.11   CLFLNS (Logical name translation)  . . . . . .  15
;        1.12   CLFJOB (Find jobs of given user) . . . . . . .  16
;        1.13   CLFMTO (Do MTOPR% function)  . . . . . . . . .  17
;        1.14   DOMTO (Section 0 MTOPR%) . . . . . . . . . . .  18
;        1.15   CLFMUT (Do remote MUTIL% request)  . . . . . .  19
;        1.16   CLFRCR/CLFRCD (RCUSR%/RCDIR% service)  . . . .  20
;        1.17   CLFSNP (Simulate SNOOP%) . . . . . . . . . . .  21
;        1.18   CLFSGT (Routine to do SYSGT%)  . . . . . . . .  22
;        1.19   CLFTMN (Routine to do TMON%) . . . . . . . . .  23
;        1.20   CLFSKD (Simulate SKED% JSYS) . . . . . . . . .  24
;        1.21   CLFXPK (Simulate XPEEK%) . . . . . . . . . . .  25
;        1.22   CLFDVC (Do the DVCHR%) . . . . . . . . . . . .  26
;        1.23   CLFSTV (Do STDEV% for remote)  . . . . . . . .  27
;        1.24   CLFDVT (Remote DEVST% working routine) . . . .  28
;        1.25   CLFNTF (Do NTINF% for remote)  . . . . . . . .  29
;        1.26   CLFGJI (Do remote GETJI% for someone)  . . . .  30
;        1.27   CLFSYS (Get SYSTAT stuff for remote) . . . . .  31
;        1.28   CLFCFG (Do CNFIG% request) . . . . . . . . . .  36
;        1.29   CLFMSR (Do MSTR%)  . . . . . . . . . . . . . .  37
;        1.30   CLFTIM (Do TIME% simulation) . . . . . . . . .  40
;        1.31   CLFTMG (Do TTMSG% request) . . . . . . . . . .  41
;        1.32   CLFBAD (Bad function from remote)  . . . . . .  42
;        1.33   CLFFAL (Send Failure)  . . . . . . . . . . . .  44
;        1.34   CLFRSP (Reassemble SCA packets)  . . . . . . .  45
;        1.35   CLFWAT (Scheduler test to wait for action) . .  46
;        1.36   ZERDAT (Zero out data area)  . . . . . . . . .  47
;        1.37   CLFSND (Routine to send results) . . . . . . .  48
;    2. End of CLUFRK  . . . . . . . . . . . . . . . . . . . .  51
	SUBTTL CLUDGR Fork -- Data Storage
NR (CLFSCR,PGSIZ)		;Scratch page for CLUDGR fork
NR (CLFREA,PGSIZ)		;Reassemble incoming data for CLUDGR fork here
	SUBTTL CLUDGR Fork -- CLSFRK (Start the CLUDGR fork)
;CLSFRK - Routine called to start the CLUDGR fork running. It is
;called by MEXEC during system startup.
;
; Call with:
;	no arguments
;	CALL CLSFRK
;
; Returns:
;	+1 - Always, CLUDGR fork number in CLFORK

	XSWAPCD			;Called at system startup

CLSFRK::MOVX T1,CR%CAP		;Give same CAPs
	CFORK%			;Make CLUDGR fork
	 ERJMP NOCLFK		;Error, let someone know about it
	MOVE T2,[XCDSEC,,CLFRUN];Start the CLUDGR fork at this address
	MSFRK%			;Do it
	 ERJMP NOCLFK		;Couldn't do it
	RET			;Done

NOCLFK:	BUG.(HLT,CLUFNC,CLUFRK,SOFT,<CLSFRK - Could not create CLUDGR fork>,<<T1,ERROR>>,<

Cause:	CFORK% was unable to create a fork for CLUDGR or MSFRK%
	was not able to start the CLUDGR fork in monitor mode.

Data:	ERROR - Error code returned from JSYS
>)				;Slight problem
	SUBTTL CLUDGR Fork -- CLFTAB (Dispatch table for CLUDGR fork)
;This table contains the legal functions that CLUDGR fork can handle.
;If the remote system requests a function that is not here, an error
;will be passed back to the remote system.

	XSWAPCD			;Put table in swap area

CLFTAB:	XADDR. CLFBAD		;Cannot do function 0 on remote node
	XADDR. CLFCFG		;Simulate CNFIG%
	XADDR. CLFDST		;Simulate DIRST%
	XADDR. CLFGTB		;Simulate GETAB%
	XADDR. CLFGJI		;Simulate GETJI%
	XADDR. CLFGTY		;Simulate GTTYP%
	XADDR. CLFINL		;Simulate INLNM%
	XADDR. CLFLNS		;Simulate LNMST%
	XADDR. CLFMSR		;Simulate MSTR%
	XADDR. CLFMTO		;Simulate MTOPR%
	XADDR. CLFMUT		;Simulate MUTIL%
	XADDR. CLFRCR		;Simulate RCUSR%
	XADDR. CLFSKD		;Simulate SKED%
	XADDR. CLFSNP		;Simulate SNOOP%
	XADDR. CLFSGT		;Simulate SYSGT%
	XADDR. CLFTMN		;Simulate TMON%
	XADDR. CLFXPK		;Simulate XPEEK%
	XADDR. CLFDVC		;Simulate DVCHR%
	XADDR. CLFNTF		;Simulate NTINF%
	XADDR. CLFSTV		;Simulate STDEV%
	XADDR. CLFDVT		;Simulate DEVST%
	XADDR. CLFSYS		;Obtain SYSTAT information
	XADDR. CLFJOB		;Get job numbers and terminals of user
	XADDR. CLFRCD		;Simulate RCDIR%
	XADDR. CLFTIM		;Simulate TIME%
TABLEN==<.-CLFTAB-1>		;Table length
	SUBTTL CLUDGR Fork -- CLFRUN (Begin running CLUDGR fork here)

;CLFRUN - This is the entry point given to the MSFRK% JSYS to
;get the CLUDGR fork started in monitor context.
;
; Called with:
;	T1/ fork handle
;	T2/ XCDSEC,,CLFRUN
;	MSFRK%
;
; Returns:
;	In theory, this routine does not return. It is the start of
;	the CLUDGR fork.
;
; [7.1132] - Note that the CLUDGR fork is bound in queue 1 much the
;same as CHKR. If this degrades performance too much, than it can be
;changed back to run as a normal process.

	XSWAPCD			;Process context

CLFRUN::MOVX T1,USRCTX		;Start with user context set
	MOVEM T1,FFL		;in PC flags
	MCENTR			;Start new process
	MOVEI T1,JP%SYS+1	;[7.1132] Clamp it in queue 1 for responsiveness
	MOVEM T1,JOBBIT		;[7.1132] Put in PSB so it is known
	MOVE T1,FORKX		;Get our fork number
	MOVEM T1,CLFORK		;And store it here for future generations
	MOVX T1,<SC%GTB!SC%WHL!SC%OPR!SC%CNF!SC%MNT!SC%IPC!SC%DNA!SC%ANA>
				;All this and privs too
	MOVEM T1,CAPMSK		;Save the capability mask
	MOVEM T1,CAPENB		;Now save as if we enabled all of them
	TRVAR <REQBLK,CODE,REQID,FRK,FLAGS,CINODE,REMUSR,REMCID> ;Temp data storage for this fork

;	REQBLK - Address of request block we are currently working on
;	CODE   - Function code to perform for remote user
;	REQID  - Request ID number from remote system
;	FRK    - Fork number from remote system
;	FLAGS  - Flags from remote system
;	CINODE - Node number of remote system
;	REMUSR - 36 bit user number of remote user
;	REMCID - CID to send reply on
CLFRN1:	HRRZI T1,CLFWAT		;Get scheduler test. No data
	MDISMS			;Now sleep until it is time to do something
CLFR15:	CALL ZERDAT		;(/) Zero out CLUDGR fork's data areas
CLFR16:	SOS CLUFLG		;Say we have seen one request
	XMOVEI Q1,CLREQQ	;Previous entry in queue is held here
	SKIPN Q2,CLREQQ		;Get entry from request queue
	JRST CLFRN1		;If there are none, then go back to sleep
CLFRN2:	MOVE T2,REQFLG(Q2)	;Get flags for this request
	TXNN T2,CL%DED		;Is this a dead letter?
	IFSKP.			;Yes, it is
	  CIOFF			;No interruptions while removing entry
	  MOVE T2,REQFLK(Q2)	;Get next request after the current one
	  MOVEM T2,REQFLK(Q1)	;And remove the current one
	  CION			;OK to let more things come in
	  MOVE T1,Q2		;Get request block
	  CALL CLFDED		;(T1/) Now return stuff
	  SKIPE CLUFLG		;Still more to do?
	  JRST CLFR16		;Yes, find it
	  JRST CLFRN1		;No, go back to sleep
	ENDIF.
	TXNN T2,CL%ALL		;Are all items here?
	IFSKP.			;Yes, remove this one
	  CIOFF			;No interruptions while diddling queue
	  MOVE T2,REQFLK(Q2)	;Get next request after the current one
	  MOVEM T2,REQFLK(Q1)	;And remove the current one
	  CION			;We done touching the queue
	  MOVE T1,Q2		;Now do the work
	  CALL CLFALL		;(T1/) Yes, time to reassemble and do some work
	  SKIPE CLUFLG		;Still more to do?
	  JRST CLFR15		;Yes, find it
	  JRST CLFRN1		;No, go back to sleep
	ENDIF.
	MOVE Q1,Q2		;Now this entry becomes the previous
	SKIPN Q2,REQFLK(Q2)	;Keep scanning queue, get next entry
	JRST CLFRN1		;There are no more, back for a nap
	JRST CLFRN2		;Have next request, check it out
	SUBTTL CLUDGR Fork -- CLFDED (Dead entry in CLREQQ)
;CLFDED - Routine to handle the dead letters in CLREQQ. We return
;things like free space and SCA buffers at this point. This routine
;can also be called when the CLUDGR fork has reassembled data for
;a request and no longer has a use for the request block and SCA
;buffers.
;
; Called with:
;	T1/ Address of request block
;	T2/ CID (when calling CLFGVB)
;	CALL CLFDED or CALL CLFGVB
;
; Returns:
;	+1 - Always, with all SCA buffers and request block returned

	XSWAPCD			;Called from process level

CLFGVB:	SAVEQ			;Preserve the work registers
	JRST CLFDD0		;Join common code
CLFDED:	SAVEQ			;Save work registers
	SETZ T2,		;Say which entry we came from
CLFDD0:	MOVE Q1,T1		;Put request block here for safe keeping
	SKIPN Q2,REQSCA(Q1)	;Get address of first SCA buffer
	JRST CLFDD2		;If no buffers then just return the request block
CLFDD1:	MOVE T3,Q2		;Get SCA buffer
	CALL GIVBCK		;(T2,T3/) And give this buffer to SCA or message free queue
	SKIPE Q2,.CLFLI(Q2)	;Get next SCA buffer
	JRST CLFDD1		;And return it
CLFDD2:	NOINT			;No interrupts whilest we return free space
	MOVE T1,Q1		;Get address of request block
	CALLX (MSEC1,RELRES)	;(T1/) And give it back
	OKINT			;Undo NOINT
	RET			;Leave the dead letter office
	SUBTTL CLUDGR Fork -- CLFALL (All buffers for a request are in)
;CLFALL - Routine called when all SCA buffers for a request on the
;CLREQQ have arrived. Dispatches to the routine to handle the request.
;
; Called with:
;	T1/ Request block address
;	CALL CLFALL
;
; Returns:
;	+1 - Always, with request responded to

	XSWAPCD			;Process level code

CLFALL:	MOVEM T1,REQBLK		;Stash request block ID here
	LOAD T2,REQFUN,(T1)	;Get function request
	MOVEM T2,CODE		;Save function code
	LOAD T2,REQNUM,(T1)	;Get remote request ID
	MOVEM T2,REQID		;Stash it in the TRVAR
	LOAD T2,.RQFRK,(T1)	;Get fork number of remote process
	MOVEM T2,FRK		;Save fork number here
	LOAD T2,.RQNOD,(T1)	;Get remote CI node number for when we answer
	MOVEM T2,CINODE		;And stash it
	MOVE T2,REQCID(T1)	;Get CID
	MOVEM T2,REMCID		;And save it for later
	MOVE T2,REQSCA(T1)	;Get address of first SCA buffer
	LOAD T3,.CLUSR,(T2)	;And get user number
	MOVEM T3,REMUSR		;Store user number
	LOAD T3,.CLFLG,(T2)	;Get flags from remote system
	HRLZM T3,FLAGS		;And save them for later if we need them
	CALL CLFRSP		;(T1/) Reassemble SCA buffers
	MOVE T1,REQBLK		;Get request block back
	MOVE T2,REMCID		;Get connect ID
	CALL CLFGVB		;(T1,T2/) Now return SCA buffers and free space
	MOVE T1,CODE		;Remote function code
	CAIN T1,CLSND		;Is it special (for TTMSG%)?
	CALLRET CLFTMG		;Yes, handle TTMSG% separately
	CAILE T1,0		;Is function in valid range?
	CAILE T1,TABLEN		;Between min and max?
	IFNSK.			;Bad function
	  MOVEI T1,INFX09	;Get error code
	  CALLRET CLFBAD	;Bad function from remote system
	ENDIF.			;Else good function, so do it
	CALLRET @CLFTAB(T1)	;Dispatch to the appropriate routine
	SUBTTL CLUDGR Fork -- CLFDST (Do DIRST for remote system)
;CLFDST - Called when remote system wants us to do a DIRST% for them.
;
; Called with:
;	CLFREA setup
;	CALL CLFDST
;
; Returns:
;	+1 - Always with data sent to remote system

	XSWAPCD			;Fork code

CLFDST:	HRROI T1,CLFSCR		;Make DIRST% put string here
	MOVE T2,CLFREA		;Get directory number
	DIRST%			;Do it
	 ERJMP DOLAST		;If error, pass error back to user
	MOVEI T1,MAXLW+1	;Send this many words back
	CALLRET CLFSND		;(T1/) Done, give remote node the string
	SUBTTL CLUDGR Fork -- CLFGTB (Do GETAB% simulation)
;CLFGTB - Routine to do a GETAB% request from a remote system.
;
; Call with:
;	CLFREA setup
;	CALL CLFGTB
;
; Returns:
;	+1 - Always, with results sent across the wire

	XSWAPCD			;Fork type code area

CLFGTB:	MOVE T1,CLFREA		;Get GETAB% argument
	GETAB%			;Do it
	 ERJMP DOLAST		;Curses, foiled again, give error back
	MOVEM T1,CLFSCR		;Stash results here for sending back
	CALLRET CL1SND		;(/) Send over 1 word
	SUBTTL CLUDGR Fork -- CLFGTY (Do GTTYP% simulation)
;CLFGTY - Simulate a GTTYP% JSYS for a remote node as per an
;INFO% request.
;
; Called with:
;	CLFREA setup
;	CALL CLFGTY
;
; Returns:
;	+1 - Always, with data sent to remote system

	XSWAPCD			;Forky codey

CLFGTY:	MOVE T1,CLFREA		;Get terminal number
	GTTYP%			;Do the JSYS shuffle
	 ERJMP DOLAST		;Looks like we can't boogie
	XMOVEI T4,CLFSCR	;Stash data here
	MOVEM T1,.AC1(T4)	;Return non-updated AC1
	MOVEM T2,.AC2(T4)	;Give user the results
	MOVEM T3,.AC3(T4)	;This is a result too
	CALLRET CL3SND		;Send over 3 words
	SUBTTL CLUDGR Fork -- CLFINL (Simulate INLNM% JSYS)
;CLFINL - Called when an INFO% request is for the INLNM% JSYS.
;
; Call with:
;	CLFREA setup
;	CALL CLFINL
;
; Returns:
;	+1 - With results sent back to requesting system

	XSWAPCD			;CLUDGR fork code

CLFINL:	MOVE T1,CLFREA		;Get index that was sent over
	HRROI T2,CLFSCR		;Put byte pointer here
	INLNM%			;Do the JSYS
	 ERJMP DOLAST		;OK, give error back to requestor
	MOVEI T1,MAXLW+1	;This is max number to send over
	CALLRET CLFSND		;(T1/) Send results back
	SUBTTL CLUDGR Fork -- CLFLNS (Logical name translation)
;CLFLNS - Translate a system logical name for a remote user.
;
; Call with:
;	CLFREA setup
;	CALL CLFLNS
;
; Returns:
;	+1 - Always, with results mailed

	XSWAPCD			;Fork fun

CLFLNS:	MOVEI T1,.LNSSY		;We only do this function
	HRROI T2,CLFREA		;User's argument is here
	HRROI T3,CLFSCR		;Put translation here
	LNMST%			;Do the translation
	 ERJMP DOLAST		;Shucks
	HRRZ T1,T3		;[7.1114] Get ending point
	AOS T1			;Make extra word in case we ended right on a word boundry
	HRRZI T3,CLFSCR		;[7.1114] Get starting point
	SUB T1,T3		;[7.1114] Subtract to find out how many words to return
	CALLRET CLFSND		;(T1/) Send over results
	SUBTTL CLUDGR Fork -- CLFJOB (Find jobs of given user)
;CLFJOB - Find all jobs and terminals of given user name string and
;pass this back to requesting system.
;
; Call with:
;	CLFREA setup
;	CALL CLFJOB
;
; Returns:
;	+1 - Always with results fired back to requesting system

	XSWAPCD			;Fork code

CLFJOB:	SAVEQ			;Save these
	STKVAR <USRNUM>		;Temp storage
	MOVX T1,RC%EMO		;We must have an exact match
	HRROI T2,CLFREA		;User name string is here
	RCUSR%			;Get user number
	 ERJMP DOLAST		;Give last error to remote system
	TXNN T1,RC%NOM		;No match?
	IFSKP.			;If not,
	  MOVEI T1,STRX08	;Say bad user name
	  CALLRET CLFBAD	;And return
	ENDIF.
	HRRZM T3,USRNUM		;Save user number for later
	XMOVEI Q2,CLFSCR	;Results go here
	AOS Q2			;Move past .JOLEN word
	MOVSI Q1,-NJOBS		;Make AOBJN pointer
	DO.			;Loop through all jobs
	  MOVE T1,JOBDIR(Q1)	;Get job's logged in number
	  CAME T1,USRNUM	;Same as the one we are looking for?
	  IFSKP.		;If so,
	    HRRZ T1,Q1		;Get local job number
	    CALLX (MSEC1,LCL2GL) ;(T1/T1) Translate it to global
	     JRST CLFBAD	;On failure, pass back error
	    HRLZS T1		;Put job number in left half
	    HLR T1,JOBPT(Q1)	;Get terminal number
	    MOVEM T1,(Q2)	;Now save terminal number
	    AOS Q2		;Bump to next data word
	    AOS CLFSCR		;Count this word
	  ENDIF.
	  AOBJN Q1,TOP.		;Do next job
	ENDDO.
	SKIPE CLFSCR		;User not logged in?
	IFSKP.			;Yes,
	  MOVEI T1,INFX07	;Say so
	  CALLRET CLFBAD	;And return to remote system with this
	ENDIF.
	AOS T1,CLFSCR		;This is how many words to send to remote node
	CALLRET CLFSND		;(T1/) Send the data and return

	ENDSV.
	SUBTTL CLUDGR Fork -- CLFMTO (Do MTOPR% function)
;CLFMTO - Called to perform some random MTOPR% function. CLUDGR fork can
;only do the functions listed in MTOTAB. If a function requested is past
;over, this system will return a INFX14 error to the remote node.
;
; Call with:
;	CLFREA setup
;	CALL CLFMTO
;
; Returns:
;	+1 - Always, with results fired over to requestor

	XSWAPCD			;Fork work code

CLFMTO:	SAVEQ			;We touch these
	XMOVEI Q2,CLFREA	;Data is in here
	MOVE T1,.AC2(Q2)	;Get user's function
	MOVSI Q1,-MTOLEN	;Make AOBJN pointer
	DO.			;Loop over all entries
	  CAMN T1,MTOTAB(Q1)	;Do we match the function?
	  EXIT.			;Yes we do, got a legal one
	  AOBJN Q1,TOP.		;No, keep scanning
	  MOVEI T1,INFX14	;Couldn't find a legal function
	  CALLRET CLFBAD	;Say so and give it to remote system
	ENDDO.
	MOVE T1,.AC1(Q2)	;Get device
	DMOVE T2,.AC2(Q2)	;Get arguments (if necessary)
	CALLX (MSEC1,DOMTO)	;[7.1104] (T1-T3/T1-T3) Do the MTOPR%
	 JRST DOLAST		;[7.1104] It failed
	XMOVEI Q2,CLFSCR	;Put results in here for remote user
	DMOVEM T1,.AC1(Q2)	;Pass this back datum
	MOVEM T3,.AC3(Q2)	;And the final one of the trilogy
	CALLRET CL3SND		;Send over 3 words
	SUBTTL CLUDGR Fork -- DOMTO (Section 0 MTOPR%)
;[7.1104]
;Note that the following section of code (no matter how gross or
;disgusting it looks) must be. MTOPR% does not work if it is executed
;outside of section 0! It assumes that T1 will have a OWGB instead
;of a universal device designator.

	SWAPCD			;Must be in section 0/1

DOMTO:	S0.ENT			;Section 0 darn it!
	MTOPR%			;Do MTOPR%
	 ERJMP R		;We had a failure
	RETSKP			;We succeeded so continue
	SUBTTL CLUDGR Fork -- CLFMUT (Do remote MUTIL% request)
;CLFMUT - Supporting routine for CLUDGR's fork to do a request
;of the MUTIL% JSYS on this node.
;
; Call with:
;	CLFREA setup
;	CALL CLFMUT
;
; Returns:
;	+1 - Always, with results mailed back to requestor

	XSWAPCD			;Fork code execution

CLFMUT:	SAVEQ			;We touch these
	XMOVEI Q2,CLFREA	;Data is in here
	MOVE T1,.AC2(Q2)	;Get user's function
	MOVSI Q1,-MUTLEN	;Make AOBJN pointer
	DO.			;Loop over all entries
	  CAMN T1,MUTTAB(Q1)	;Do we match the function?
	  EXIT.			;Yes we do, got a legal one
	  AOBJN Q1,TOP.		;No, keep scanning
	  MOVEI T1,INFX14	;Couldn't find a legal function
	  CALLRET CLFBAD	;Say so and give it to remote system
	ENDDO.
	MOVEM T1,CLFSCR		;Put function in our argument block
	MOVE T1,.AC1(Q2)	;Get remote user's argument block size
	XMOVEI T2,CLFSCR	;Here's our MUTIL% return address
	MUTIL%			;Get the information
	 ERJMP DOLAST		;Pass back our failure
	CALLRET CLFSND		;(T1/) And give to remote user
	SUBTTL CLUDGR Fork -- CLFRCR/CLFRCD (RCUSR%/RCDIR% service)
;CLFRCR/CLFRCD - Called when the remote system needs an RCUSR%/RCDIR%
;JSYS done on this node.
;
; Call with:
;	CLFREA setup
;	CALL CLFRCR
;	    or
;	CALL CLFRCD
;
; Returns:
;	+1 - Always, with results filed to remote system

	XSWAPCD			;Fork code

CLFRCR:	SKIPA T1,[RCUSR]	;Flag that an RCUSR% is to be done
CLFRCD:	MOVE T1,[RCDIR]		;Flag we want RCDIR%
	SAVEQ			;Save the temps
	STKVAR <DOJSYS>		;Place to save the JSYS
	MOVEM T1,DOJSYS		;Save the JSYS to do
	XMOVEI Q1,CLFREA	;Here's where the data is
	MOVE T1,.AC1(Q1)	;Get the flags
	MOVE T3,.AC2(Q1)	;Get the user/directory number in case of stepping
	XMOVEI T2,.AC3(Q1)	;Now for the user/directory name
	HRLI T2,(POINT 7,)	;Make it a 7 bit byte pointer
	XCT DOJSYS		;Do the simulation
	 ERJMP DOLAST		;When failing, give error back to remote
	XMOVEI Q1,CLFSCR	;Here's the data page to stash results in
	MOVEM T1,.AC1(Q1)	;Pass back these flags
	MOVEM T3,.AC2(Q1)	;Now pass back the user/directory number
	CALLRET CL3SND		;Send over 3 words

	ENDSV.
	SUBTTL CLUDGR Fork -- CLFSNP (Simulate SNOOP%)
;CLFSNP - Routine to make CLUDGR fork do a SNOOP% JSYS for a remote
;node.
;
; Call with:
;	CLFREA setup
;	CALL CLFSNP
;
; Returns:
;	+1 - Always, with results sent back

	XSWAPCD			;Fork code

CLFSNP:	MOVE T1,CLFREA		;Get function code from remote
	CAIN T1,.SNPSY		;Is it this?
	JRST CLFSP1		;Yes, do it
	CAIN T1,.SNPAD		;Or this?
	IFSKP.			;If neither,
	  MOVEI T1,INFX14	;Then say we don't do this
	  CALLRET CLFBAD	;And give it to remote caller
	ENDIF.
CLFSP1:	XMOVEI Q1,CLFREA	;Now get symbol name
	MOVE T2,.AC2(Q1)	;Here it is, do the JSYS
	MOVE T3,.AC3(Q1)	;Get this argument too
	SNOOP%			;Do the work
	 ERJMP DOLAST		;If failure, let user know
	XMOVEI T1,CLFSCR	;Here's where the data is going
	DMOVEM T2,.AC2(T1)	;Stash T2 and T3
	CALLRET CL3SND		;Send over 3 words
	SUBTTL CLUDGR Fork -- CLFSGT (Routine to do SYSGT%)
;CLFSGT - Called by CLUDGR fork to handle a remote request for
;SYSGT% JSYS.
;
; Call with:
;	CLFREA setup
;	CALL CLFSGT
;
; Returns:
;	+1 - Always, with results federal expressed to requesting CI node

	XSWAPCD			;Fork code

CLFSGT:	MOVE T1,CLFREA		;Get SIXBIT name
	SYSGT%			;Do the JSYS shuffle
	 ERJMP DOLAST		;Handle badness
	DMOVEM T1,CLFSCR	;Here's the results
	CALLRET CL2SND		;Send over 2 words
	SUBTTL CLUDGR Fork -- CLFTMN (Routine to do TMON%)
;CLFTMN - Called by CLUDGR fork to handle a remote request for
;TMON% JSYS.
;
; Call with:
;	CLFREA setup
;	CALL CLFTMN
;
; Returns:
;	+1 - Always, with results federal expressed to requesting CI node

	XSWAPCD			;Fork code

CLFTMN:	MOVE T1,CLFREA		;Get function code
	TMON%			;Do the JSYS shuffle
	 ERJMP DOLAST		;Handle badness
	XMOVEI T1,CLFSCR	;Return setting here
	MOVEM T2,.AC2(T1)	;Here's the results
	CALLRET CL2SND		;Send over 2 words
	SUBTTL CLUDGR Fork -- CLFSKD (Simulate SKED% JSYS)
;CLFSKD - Called when the remote system has requested a SKED% function.
;Legal remote SKED% functions are in SKDTAB.
;
; Call with:
;	CLFREA setup
;	CALL CLFSKD
;
; Returns:
;	+1 - Always, with results sent to requesting system

	XSWAPCD			;Process level code

CLFSKD:	SAVEQ			;Save the quasi's
	MOVE T1,CLFREA		;Get function code
	MOVSI Q1,-SKDLEN	;Scan table for legal functions
	DO.			;Loop through each entry
	  CAMN T1,SKDTAB(Q1)	;Good function?
	  EXIT.			;Yes, do it
	  AOBJN Q1,TOP.		;No, check the next one
	  MOVEI T1,INFX14	;Couldn't find this one, can't do it
	  CALLRET CLFBAD	;Say naughty, naughty to remote system
	ENDDO.
	XMOVEI Q2,CLFREA	;Now that we have a function, get arg block length
	XMOVEI T2,CLFSCR	;Return data here when we JSYS
	MOVE T3,.AC2(Q2)	;Argument block length here
	MOVEM T3,.SACNT(T2)	;Save our argument block lenght for JSYS
	MOVE T3,.AC3(Q2)	;Get job number (if necessary)
	MOVEM T3,.SAJOB(T2)	;Save it for JSYS
	SKED%			;Do it
	 ERJMP DOLAST		;If failed, handle error
	MOVEI T1,<.SACLU+1>	;Succeeded, only send maximum possible block back
	CALLRET CLFSND		;(T1/) And do the send
	SUBTTL CLUDGR Fork -- CLFXPK (Simulate XPEEK%)
;CLFXPK - Called when a remote system has a request for the local system
;to handle and this request is to do an XPEEK% on the local system.
;
; Call with:
;	CLFREA setup
;	CALL CLFXPK
;
; Returns:
;	+1 - Always, with results set to requesting system

	XSWAPCD			;Fork code

CLFXPK:	XMOVEI T1,CLFSCR	;Place results in this page
	XMOVEI T2,CLFREA	;Our argument block is here
	MOVEM T1,.XPUAD(T2)	;Store destination data area in argument block
	MOVE T1,.XPCN1(T2)	;Get requested size
	CAIG T1,PGSIZ		;Small enough?
	IFSKP.			;If not,
	  MOVEI T1,INFX17	;Say this is too big
	  CALLRET CLFBAD	;And pass back this error code
	ENDIF.
	XMOVEI T1,CLFREA	;Here's the argument block
	XPEEK%			;Do the work
	 ERJMP DOLAST		;We had an error, let remote know about it
	MOVE T1,.XPCN2(T1)	;This is how many words to send back
	CALLRET CLFSND		;(T1/) Now send them
	SUBTTL CLUDGR Fork -- CLFDVC (Do the DVCHR%)
;CLFDVC - Routine called when CLUDGR fork has a request to do a
;DVCHR% JSYS.
;
; Call with:
;	CLFREA setup
;	CALL CLFDVC
;
; Returns:
;	+1 - Always, with results returned to remote system

	XSWAPCD			;Fork code

CLFDVC:	MOVE T1,CLFREA		;Get device designator
	DVCHR%			;Do the JSYS
	 ERJMP DOLAST		;We failed
	XMOVEI T4,CLFSCR	;Here's where returned data goes
	DMOVEM T1,.AC1(T4)	;Save this as returned data
	MOVEM T3,.AC3(T4)	;And last but not least this too
	CALLRET CL3SND		;Push over 3 words
	SUBTTL CLUDGR Fork -- CLFSTV (Do STDEV% for remote)
;CLFSTV - Called when a request has been received to simulate the
;STDEV% JSYS on this system.
;
; Call with:
;	CLFREA setup
;	CALL CLFSTV
;
; Returns:
;	+1 - Always, with results flown back on the CI

	XSWAPCD			;Fork like code

CLFSTV:	HRROI T1,CLFREA		;Here's the device name
	STDEV%			;Get device designator
	IFJER.			;When failed,
	  MOVE T1,T2		;Error code in wrong AC
	  CALLRET CLFBAD	;Pass it back to requestor
	ENDIF.
	XMOVEI T1,CLFSCR	;Here's where to store device designator
	MOVEM T2,.AC2(T1)	;Store results
	CALLRET CL2SND		;Send over 2 words
	SUBTTL CLUDGR Fork -- CLFDVT (Remote DEVST% working routine)
;CLFDVT - Routine called to do the work for a request that a DEVST%
;monitor call be performed on this system with results given back
;to remote system.
;
; Call with:
;	CLFREA setup
;	CALL CLFDVT
;
; Returns:
;	+1 - Always, with results fired back to requestor

	XSWAPCD			;Fork type code

CLFDVT:	HRROI T1,CLFSCR		;Make DEVST% put string here
	MOVE T2,CLFREA		;Get device designator
	DEVST%			;Do it
	 ERJMP DOLAST		;If error, pass error back to user
	MOVEI T1,MAXLW+1	;Send this many words back
	CALLRET CLFSND		;(T1/) Done, give remote node the string
	SUBTTL CLUDGR Fork -- CLFNTF (Do NTINF% for remote)
;CLFNTF - Called when CLUDGR fork has a request for a NTINF% JSYS
;and this system is the sucker to handle the request.
;
; Call with:
;	CLFREA setup
;	CALL CLFNTF
;
; Returns:
;	+1 - Always, with results sent back

	XSWAPCD			;Fork code

CLFNTF:	SAVEQ			;We use these politely
	XMOVEI T1,CLFSCR	;Here's the argument block for the JSYS
	XMOVEI Q1,CLFREA	;Here's the passed over data
	MOVE T2,.NWABC(Q1)	;Get argument block count
	MOVEM T2,.NWABC(T1)	;Prepare it for JSYS
	MOVE T2,.NWFNC(Q1)	;Get function code
	MOVEM T2,.NWFNC(T1)	;Save in argument block
	SKIPL T2,.NWLIN(Q1)	;Get terminal number
	IFSKP.			;If -1,
	  MOVEI T1,INFX14	;Say this is bad
	  CALLRET CLFBAD	;And pass back the error
	ENDIF.
	MOVEM T2,.NWLIN(T1)	;Save in argument block
	HRROI T2,CLFSCR		;Make a byte pointer for destination name
	ADDI T2,<.NWNU1+2>	;And make it point past argument block
	MOVEM T2,.NWNNP(T1)	;Save it in argument block
	NTINF%			;Do the JSYS
	 ERJMP DOLAST		;Tell remote something went wrong
	MOVEI T1,<.NWNU1+2+3*MAXLW> ;This is how many to send back
	CALLRET CLFSND		;(T1/) Send it back
	SUBTTL CLUDGR Fork -- CLFGJI (Do remote GETJI% for someone)
;CLFGJI - Supporting routine to handle a GETJI% request from another
;node.
;
; Call with:
;	CLFREA setup
;	CALL CLFGJI
;
; Returns:
;	+1 - Always, with results rifled back to requestor

	XSWAPCD			;Process level code

CLFGJI:	SAVEPQ			;Save these
	XMOVEI Q1,CLFREA	;Reassembled data is here
	XMOVEI Q2,CLFSCR	;New ACs and results go here for return flight
	SKIPL T1,.AC1(Q1)	;Get job number/tty number
	IFSKP.			;If -1,
	  MOVEI T1,INFX14	;Then no can do
	  CALLRET CLFBAD	;And tell other system
	ENDIF.
	HLLZ T2,.AC2(Q1)	;Get -count into this AC
	HRR T2,Q2		;Get argument block address
	ADDI T2,3		;Bump past 3 ACs to be sent back
	MOVE T3,.AC3(Q1)	;Now get offset of first entry
	MOVEI P1,.JISRM		;Here's the session remark word
	SUB P1,T3		;See if session remark requested
	IFGE. P1		;Session remark needed?
	  MOVEI P2,CLFSCR	;Stuff goes here
	  ADDI P2,<3+.JILJI+1>	;Session remark starts here
	  HRROS P2		;Make it a byte pointer
	  MOVEM P2,CLFSCR(P1)	;Save session remark byte pointer here
	ENDIF.			;Now do the JSYS
	GETJI%			;Get the information
	 ERJMP DOLAST		;It didn't work
	MOVEM T1,.AC1(Q2)	;Save updated this
	MOVEM T2,.AC2(Q2)	;Save updated that
	MOVEM T3,.AC3(Q2)	;Save updated the other thing
	MOVEI T1,<3+.JILJI+MAXLW> ;Make sure we send this many words
	CALLRET CLFSND		;(T1/) Give results to remote system
	SUBTTL CLUDGR Fork -- CLFSYS (Get SYSTAT stuff for remote)
;CLFSYS - Called when a request on the CLUDGR request queue is asking
;for some SYSTAT information for a particular job/terminal.
;
; Call with:
;	CLFREA setup
;	CALL CLFSYS
;
; Returns:
;	+1 - Always, with results sent to requesting node
;
; Note, this routine returns data in this order:
;Word 0 - Program name
;Word 1 - Controlling TTY
;Word 2 - Controlling job
;Word 3 - Global job number
;Word 4 - (-1=RUN) or (0=TI) state
;Word 5 - Job runtime
;Word 6 - Runtime limit
;Word 7 - Job class
;Word 10 - Job share
;Word 11 - Job use
;Word 12-21 - User name string
;Word 22-41 - Connected directory string
;Word 42-71 - Origin string

	XSWAPCD			;Fork code

CLFSYS:	SAVEPQ			;These are abused
	STKVAR <JOB,TTY,<SKDBLK,7>,<NTNBLK,10>,<ORGSTR,3*MAXLW>> ;Temp storage
	MOVE T1,CLFREA		;Get job/terminal number
	TXZN T1,.TTDES		;Did remote user give us a terminal?
	IFSKP.			;If so,
	  MOVEM T1,TTY		;Save terminal number for later
	  CAIL T1,0		;Make sure terminal number is in range
	  CAILE T1,NLINES	;Is it?
	  IFNSK.		;No,
	    MOVEI T1,GTJIX2	;Say terminal out of range
	    CALLRET CLFBAD	;And give it back to remote user
	  ENDIF.
	  MOVE T2,TTY		;Get terminal in correct AC
	  NOSKED		;Not while we are touching TTY database stuff
	  CALLX (MSEC1,GTCJOB)	;(T2/T3) Get controlling job number
	  IFNSK.		;If none,
	    OKSKED		;We are done
	    CALLRET CLFBAD	;And give the error back to remote system
	  ENDIF.
	  OKSKED		;Terminal data base done being looked at
	  MOVEM T3,JOB		;Save job number for later
	ELSE.			;If no,
	  CALLX (MSEC1,GL2LCL)	;(T1/T1) Get local job number
	   CALLRET CLFBAD	;Failed, tell remote system
	  MOVEM T1,JOB		;And save it
	ENDIF.
	NOINT			;Don't bother me while I get the job's JSB
	MOVE T1,JOB		;Get job number
	CALLX (MSEC1,MAPJSB)	;(T1/T1) Map in foreign JSB
	IFNSK.			;If no job,
	  OKINT			;Interrupts are OK
	  MOVEI T1,GTJIX4	;Say so
	  CALLRET CLFBAD	;And send back our response
	ENDIF.
	MOVE Q2,T1		;Save JSB offset for use later
	XMOVEI Q1,CLFSCR	;Store data in the scratch area
	MOVE T1,JOB		;Get job number
	MOVE T2,JOBPNM(T1)	;Get job program name
	MOVEM T2,(Q1)		;Save it in send block
	AOS Q1			;Move on to next word in block
	MOVE T2,CTRLTT(Q2)	;Get controlling terminal
	MOVEM T2,(Q1)		;Save it for sending
	MOVEM T2,TTY		;Also, make sure we have TTY number
	AOS Q1			;Get ready for next datum
	NOSKED			;Again, NOSKED while getting TTY stuff
	CALLX (MSEC1,GTCJOB)	;(T2/T3) Get controlling terminal for this job
	IFNSK.			;If failed,
	  OKSKED		;Allow scheduling
	  CALLX (MSEC1,CLRJSB)	;(/) Clear our JSB mapping and go OKINT
	  MOVEI T1,GTJIX2	;Say error
	  CALLRET CLFBAD	;And return info to remote node
	ENDIF.
	OKSKED			;We now have the controlling job
	MOVEM T3,(Q1)		;Store it for sending
	AOS Q1			;Move on to next word
	MOVE T1,JOB		;Retrieve local job number
	CALLX (MSEC1,LCL2GL)	;(T1/T1) Get global job number
	IFNSK.			;If failure (shouldn't happen)
	  CALLX (MSEC1,CLRJSB)	;(/) Clear JSB mapping
	  CALLRET CLFBAD	;And give error back to caller
	ENDIF.
	MOVEM T1,(Q1)		;Save job number in data area
	MOVE P2,T1		;Get global job here for later
	AOS Q1
	SKIPGE T2,TTY		;Get TTY back
	IFSKP.			;If line is active,
	  MOVE T1,TTACTL(T2)	;Get line block
	  LOAD T1,TWFRK,(T1)	;Get forks waiting for TI
	  SETOM (Q1)		;Assume running
	  CAIE T1,-1		;Is it running
	  SETZM (Q1)		;No, say TI
	ENDIF.
	AOS Q1			;Bump to next data word
	MOVE T1,JOBRT(P1)	;Get job runtime too
	MOVEM T1,(Q1)		;It is going to be passed back
	AOS Q1			;Next...
	MOVE P1,JOB		;Get job number for this AC
	CALL GETRTL		;[7.1200] (P1/T1) Get runtime limit
	MOVEM T1,(Q1)		;Save it here
	AOS Q1			;Next data item
	SKIPN CLASSF		;[7.1105] Class scheduling on?
	IFSKP.			;If so,
	  MOVEI T2,SKDBLK	;Put SKED% results here
	  MOVEI T1,7		;Argument block length
	  MOVEM T1,.SACNT(T2)	;Save count for JSYS
	  MOVEM P2,.SAJOB(T2)	;Stash global job in arg block
	  MOVEI T1,.SKRJP	;Read job parameters
	  SKED%			;From scheduler database
	  IFJER.		;If we failed,
	    CALLX (MSEC1,CLRJSB) ;(/) Clear JSB mapping
	    CALLRET DOLAST	;And past back our process error to remote
	  ENDIF.
	  MOVE T1,.SAJCL(T2)	;Get job's class
	  MOVEM T1,(Q1)		;Save for sending
	  AOS Q1		;Move on to next storage word
	  MOVE T1,.SAJSH(T2)	;Get job's share
	  MOVEM T1,(Q1)		;Pass it along
	  AOS Q1		;Next word
	  MOVE T1,.SAJUS(T2)	;Now for utilization
	  MOVEM T1,(Q1)		;Save it too
	  AOS Q1		;Now ready for byte strings
	ELSE.			;Class scheduling was not on
	  ADDI Q1,3		;So account for the three words we didn't fill in
	ENDIF.
	MOVE P2,JOB		;Get local job number
	SKIPE T1,JOBDIR(P2)	;Get logged in directory
	IFSKP.			;If not logged in
	  MOVEI T1,3		;Then blast not logged in string
	  XMOVEI T2,NOTLOG	;Here's the string
	ELSE.			;Else, user for real
	  MOVEI T1,MAXLW	;This is how many words for user name string
	  XMOVEI T2,USRNAM(Q2)	;User name stored here in JSB
	ENDIF.
	AOS T2			;But text starts one word later
	XMOVEI T3,(Q1)		;Put user name here
	CALLX (MSEC1,XBLTAT)	;(T1,T2,T3/T1,T2,T3) Blast user name in block
	ADDI Q1,MAXLW		;Account for user name
	MOVE T2,JSBSDN(Q2)	;Get connected directory number
	HRRO T1,Q1		;Now put in connected directory string
	DIRST%			;Get it from monitor
	IFJER.			;If failed,
	  HRROI T2,[ASCIZ /?/]	;Say we don't know
	  SETZB T3,T4		;Terminate on the null
	  SOUT%			;Put "?" in data area
	   ERJMP .+1		;Shouldna happen
	ENDIF.
	ADDI Q1,2*MAXLW		;Now blow past connected directory string
	CALLX (MSEC1,CLRJSB)	;(/) Clear foreign JSB mapping and go OKINT
	MOVEI T1,NTNBLK		;NTINF% info goes here
	SETZM .NWFNC(T1)	;Say function .NWRHH
	MOVEI T2,ORGSTR		;Destination string goes here
	HRROM T2,.NWNNP(T1)	;Store it in NTINF% argument block
	MOVEI T2,10		;Count of words in NTINF% block
	MOVEM T2,.NWABC(T1)	;Tell JSYS how many
	MOVE T2,TTY		;Get terminal back
	TXO T2,.TTDES		;Make it TTY device designator
	MOVEM T2,.NWLIN(T1)	;Save for NTINF%
	NTINF%			;Do the JSYS
	 ERJMP CLFSY2		;If failed, don't care
	MOVE Q2,.NWTTF(T1)	;Get terminal origin flags
	LDB Q2,[POINT 9,Q2,17]	;Get flags
	CAIN Q2,NW%NNT		;Non network terminal?
	JRST CLFSY2		;Yes, send off data to remote
	HRROI T2,ORGSTR		;Get origin node
	HRRO T1,Q1		;Get destination of origin string
	SETZB T3,T4		;Terminate on null
	SOUT%			;Blast string
	 ERJMP .+1		;Never happens
	MOVEI T2,NTNBLK		;Now find out what kind of terminal it was
	MOVE T2,.NWTTF(T2)	;Get type word
	LDB T2,[POINT 9,T2,17]	;Only get these flags
	CAIE T2,NW%TCP		;TCP terminal?
	IFSKP.			;If so,
	  HRROI T2,SYSTCP	;Say so
	  JRST CLFSY1		;And put it in
	ENDIF.
	MOVEI T2,NTNBLK		;Not TCP, get other flags
	HRRZ T2,.NWTTF(T2)	;Here they are
	CAIE T2,NW%LH		;LAT terminal?
	IFSKP.			;If so,
	  HRROI T2,SYSLAT	;Get LAT origin string
	  JRST CLFSY1		;And put it in
	ENDIF.
	CAIE T2,NW%CH		;CTERM terminal?
	IFSKP.			;If so,
	  HRROI T2,SYSCTM	;Put CTM in string
	  JRST CLFSY1		;Do it
	ENDIF.
	HRROI T2,SYSNRT		;Must be a NRT terminal then
CLFSY1:	SETZB T3,T4
	SOUT%
	 ERJMP .+1
	ADDI Q1,3*MAXLW		;Account for origin in block to be returned	
CLFSY2:	MOVE T1,Q1		;Get current scratch page pointer
	XMOVEI T2,CLFSCR	;Get scratch page address
	SUB T1,T2		;This is how many words to send to remote system
	CALLRET CLFSND		;(T1/) Do the send and return to process more requests

	ENDSV.
	SUBTTL CLUDGR Fork -- CLFCFG (Do CNFIG% request)
;CLFCFG - Called when it is time to do a CNFIG% for a remote system.
;
; Call with:
;	CLFREA setup
;	CALL CLFCFG
;
; Returns:
;	+1 - Always, with results sent back to requestor

	XSWAPCD			;Process level stuff

CLFCFG:	XMOVEI T2,CLFSCR	;Put results in this space
	XMOVEI T1,CLFREA	;Get function code and length or argument block
	MOVE T3,1(T1)		;This is the length of the argument block
	MOVEM T3,CLFSCR		;Store length here for CNFIG%
	MOVE T1,CLFREA		;Get function code for us to do
	CNFIG%			;Get the data
	 ERJMP DOLAST		;Get last error and pass it across CI
	MOVEI T1,<4*HSTSIZ>	;Send back this many words
	CALLRET CLFSND		;(T1/) Now send reponse back
	SUBTTL CLUDGR Fork -- CLFMSR (Do MSTR%)
;CLFMSR - Routine that does an MSTR% JSYS on behalf of the remote
;system
;
; Called with:
;	CLFREA setup
;	CALL CLFMSR
;
; Returns:
;	+1 - Always, with reponse mailed to reqesting system

	XSWAPCD			;CLUDGR Fork man

CLFMSR:	SAVEQ			;Save quasi preserved thingies
	XMOVEI Q2,CLFREA	;Get reassembled data area
	XMOVEI Q3,CLFSCR	;Working page area
	HRR T1,.AC1(Q2)		;Get user's function
	CAIN T1,.MSGSS		;Is it this function?
	JRST CLMSR2		;OK, don't need privs neither
	CAIN T1,.MSGSU		;How about this one?
	JRST CLMSR2		;Yep, don't check privs
	CAIN T1,.MSRNU		;Or maybe this?
	JRST CLMSR1		;Check privs first
	CAIN T1,.MSRUS		;This is it...
	IFSKP.			;The function given was bad
	  MOVEI T1,INFX14	;Say we can't do this function
	  CALLRET CLFBAD	;And return
	ENDIF.
CLMSR1:	MOVE T1,FLAGS		;Get user flags
	TXNE T1,CL%PRV!CL%GAL	;Is remote GALAXY or prived?
	IFSKP.			;Tis neither
	  MOVEI T1,MSTRX2	;No privs, chump
	  CALLRET CLFBAD	;Get outta here
	ENDIF.
CLMSR2:	HRRZ Q1,T1		;Save the function briefly	
	XMOVEI T3,CLFSCR	;This is where to put responses
	XMOVEI T2,CLFREA	;User's arg block is down passed
	ADDI T2,.INMAX		;These many words in CLFREA
	HLRZ T1,.AC1(Q2)	;Get count of arg block
	CAIG T1,.MSRLN		;Is it too big?
	IFSKP.			;If so,
	  MOVEI T1,.MSRLN	;This is the max
	  HRLM T1,.AC1(Q2)	;And correct for it
	ENDIF.
	CALLX (MSEC1,XBLTAT)	;(T1-T3/T1-T3) Get it from CLFREA and put in CLFSCR
	CAIE Q1,.MSRNU		;If this function or
	CAIN Q1,.MSRUS		;If this function, then no structure either
	JRST CLMR35		;Set up byte pointers for return
	SKIPL T1,.INMAX(Q2)	;Get "byte pointer" to structure
	JRST CLMSR3		;No byte pointer, we have device designator
	MOVEI T1,<.INMAX+.MSRLN+1> ;[7.1094] Byte string starts at this offset
	ADD T1,Q2		;Get absolute address of byte string
	HRROM T1,(Q3)		;[7.1094] Make this -1,,addr of structure string
CLMSR3:	CAIE Q1,.MSGSS		;Must we check for physical ID too?
	JRST CLMSR4		;No, get the MSTR% data
	MOVEI T1,<.INMAX+.MSGLN> ;Find string to put physical str name
	ADD T1,Q2		;Get the absolute offset
	SKIPL (T1)		;If don't want this,
	JRST CLMSR4		; then fine, go on
	MOVEI T1,<.INMAX+.MSGLN> ;Put physical name byte pointer at this offset
	ADD T1,Q3		;In scratch area to be sent back
	HRROM T1,.MSGSI(Q3)	;[7.1094] Stick byte pointer here in arg block
	JRST CLMSR4		;Now do the MSTR%
;Here to set up structure name and alias byte pointers.
CLMR35:	XMOVEI T1,CLFSCR	;Get scratch pad
	XMOVEI T2,.MSRLN(T1)	;This is where byte pointer is going
	HRROS T2		;Make byte pointer
	MOVEM T2,.MSRSN(T1)	;Put byte pointer here
	ADDI T2,2		;Alias goes 2 words later
	MOVEM T2,.MSRSA(T1)	;Put it in MSTR% arg block
CLMSR4:	MOVE T1,Q1		;Get function back
	HLL T1,.AC1(Q2)		;Put arg block length here too
	XMOVEI T2,CLFSCR	;Make MSTR% put results here
	MSTR%			;Do the MSTR%
	 ERJMP DOLAST		;Return last error to our requestor
	MOVEI T1,<.INMAX+.MSRLN+MAXLW+1> ;Give back this many words
	CALLRET CLFSND		;(T1/) Data page now ready to be sent
	SUBTTL CLUDGR Fork -- CLFTIM (Do TIME% simulation)
;CLFGTB - Routine to do a TIME% request from a remote system.
;
; Call with:
;	CLFREA setup
;	CALL CLFTIM
;
; Returns:
;	+1 - Always, with results sent across the wire

	XSWAPCD			;Fork type code area

CLFTIM:	MOVE T1,TODCLK		;Here's our uptime
	MOVEM T1,CLFSCR		;Stash results here for sending back
	CALLRET CL1SND		;Send only 1 word
	SUBTTL CLUDGR Fork -- CLFTMG (Do TTMSG% request)
;CLFTMG - This is called when in coming packets represent a request for
;a remote TTMSG% and this node is the sucker to do the work. It always
;sends back a one word reply. This word either contains an error code
;when we failed or it has 0 meaning we succeeded.
;
; Call with:
;	CLFREA setup
;	CALL CLFTMG
;
; Returns:
;	+1 - Always, with results sent back to requestor

	XSWAPCD			;Fork context code

CLFTMG:	XMOVEI T2,CLFREA	;Here's where we find it all
	MOVE T1,(T2)		;This gets the terminal designator
	MOVE T3,FLAGS		;Get flags from remote system
	TXNE T3,CL%PRV!CL%GAL	;Check to see if prived or GALAXY
	IFSKP.			;If not,
	  CAIE T1,.TTTTY	;If user wants all terminals
	  IFSKP.		;If so, and he ain't prived,
	    MOVEI T1,GTDIX1	;Say he needs privs
	    CALLRET CLFBAD	;And get out of here
	  ENDIF.
	  TXZ T1,.TTDES		;Clear terminal designator and just get line #
	  CAIL T1,0		;Range check the line
	  CAILE T1,NLINES	;Is it within range?
	  JRST CLFTM1	    	;No, just TTMSG%, it will fail and then pass back error
	  JN TTNTM,(T1),NOTMG	;User inhibiting?
	  JE TTNUM,(T1),CLFTM1	;Or is he refusing user messages?
	  JRST NOTMG		;Yes, can't let this go
	ELSE.
	  CAIN T1,.TTTTY	;Want all terminals?
	  SETO T1,		;Yes, flag so
	ENDIF.
CLFTM1:	TXO T1,.TTDES		;Make .TTDES again
	AOS T2			;Now this is where the send all stuff is
	HRLI T2,(POINT 7,)	;Stuff was sent over in 7 bit
	TTMSG%			;The the TTMSG% for the user
	 ERJMP ERRTMG		;Do last error
	SETZM CLFSCR		;This indicates send was successful
	CALLRET CL1SND		;Send over 1 word

ERRTMG:	SKIPA T1,LSTERR		;Get last error
NOTMG:	MOVEI T1,TTMSX2		;User refusing
	TXO T1,IN%RER		;Say error from remote
	CALLRET CLFBAD		;Tell remote system
	SUBTTL CLUDGR Fork -- CLFBAD (Bad function from remote)
;CLFBAD - Routine to handle a bad function or error. We get here when a
;remote system sends us a CLUDGR request but we can't do it because it is
;not in our dispatch table or if we tried to do the request and some kind of
;error occurred while executing the request.
;
; Call with:
;	T1/ Error code (if 0, error code gotten out of LSTERR)
;	CALLRET CLFBAD
;	    or
;	CALLRET DOLAST (when LSTERR is to be used)
;
; Returns:
;	+1 - Always with remote system notified

	XSWAPCD			;Done at process level

DOLAST:	SETZ T1,		;Here when we want LSTERR
CLFBAD:	STKVAR <ERROR,RETADR,TRIES,SCABUF> ;Place to save error code
	SKIPN T1		;If nothing passed in,
	MOVE T1,LSTERR		;then get our last error
	MOVEM T1,ERROR		;Save error code whilest we get SCA buffer
	MOVEI T1,1		;Tell SCA we only want a single buffer
	CALL <XENT SC.ABF>	;(T1/T1,T2,T3) get an SCA buffer
CLFNOB:	 BUG. (HLT,CLUOSB,CLUFRK,SOFT,<CLUDGR fork could not get an SCA buffer>,,<

Cause:	A request was made for CLUDGR fork to do something. Unfortunately,
	this request failed for one reason or another. When CLUDGR fork
	tried to tell the remote system it failed, the fork could not
	get an SCA buffer to reply. This should not happen as SCA uses
	an entire section for buffers.
>)				;What do you mean no buffers?
	MOVEM T3,RETADR		;This is where return buffer
	MOVEM T1,SCABUF		;Save SCA buffer address
	AOS CLUBUF		;Say another buffer in use by CLUDGR
	MOVX T2,CL%REQ		;Say this is a response
	ANDCAM T2,FLAGS		;By clearing this bit
	MOVX T2,CL%ERR		;Now say we had an error
	IORM T2,FLAGS		;By setting this bit
	BLCAL. (FILLIN,<T1,FLAGS,REQID,CODE,FRK,CINODE,REMUSR,[1]>) ;[7.1090]
				;[7.1090] Fill in SCA buffer chain
	MOVE T1,SCABUF		;Get SCA buffer address back
	MOVE T2,ERROR		;Get error code back
	MOVEM T2,CLDATA(T1)	;Store error in data area
	MOVEI T2,MAXTRY		;Get max tries
	MOVEM T2,TRIES		;And init our tries counter
	MOVE T2,REMCID		;Send response on this CID
CLFBD1:	MOVE T1,SCABUF		;Put SCA buffer address here for send
	BLCAL. (<XENT SC.SMG>,<T2,[F.RTB+F.SPM],[CLDATA+1],T1,[CLUPRI],[0],[0]>) ;[7.1090]
	IFNSK.			;Send failed
	  CAIE T1,SCSNEC	;Was it due to insufficient credit?
	  JRST CLFBD2		;No, ignore it then
	  SOSGE TRIES		;Add this failure. Have we tried enough?
	  CALL CLFFAL		;(/) Yes, CRASH!
	  MOVEI T1,WAIT		;Sleep for a bit
	  DISMS%
	  JRST CLFBD1		;And try to send again
	ENDIF.
CLFBD2:	RET			;And finished
	ENDSV.
	SUBTTL CLUDGR Fork -- CLFFAL (Send Failure)
;CLFFAL - Here when the CLUDGR fork tried to send something MAXTRY
;times. Now we BUGHLT.
;
; Called with:
;	no arguments
;	CALL CLFFAL
;
; Returns:
;	NEVER

	XSWAPCD			;Called by fork

CLFFAL:	BUG. (HLT,CLUSCM,CLUFRK,SOFT,<CLUDGR fork send unconditionally failed>,,<

Cause:	The local system attempted to send a response to a remote system
	MAXTRY times. This BUGHLT indicates that the send failed each
	time due to lack of receive credit on the remote system. The
	system must be sucking all of the credits somehow. However, simply
	not performing the send will hang a fork on the remote system.
	At least the fork will wake up.
>)				;Crash
	SUBTTL CLUDGR Fork -- CLFRSP (Reassemble SCA packets)
;CLFRSP - Routine called to reassemble a collection of SCA buffers
;associated with a request that was on the CLREQQ.
;
; Called with:
;	T1/ Address of request block
;	CALL CLFRSP
;
; Returns:
;	+1 - Always, with data in SCA packets reassembled in the CLFREA page

	XSWAPCD			;Process level code

CLFRSP:	SAVEAC <Q1>		;Save scratch spot
	XMOVEI T3,CLFREA	;Start putting stuff at this location
	SKIPN Q1,REQSCA(T1)	;Get first SCA buffer
	BUG. (HLT,CLFNSB,CLUFRK,SOFT,<No SCA buffers for request>,,<

Cause:	This BUG indicates that a request came in from a remote system
	for the local CLUDGR fork to perform. However, after the CL%ALL
	bit was set in the request block, there were no SCA buffers to
	reassemble. CL%ALL must have been erroneously set.
>)				;If no SCA buffers, die now
	AOS Q3,CLDLEN(Q1)	;[7.1090] Get words we received
CLFRS1:	LOAD T2,.CLPTR,(Q1)	;Get pointer to data area
	ADDI T2,CLDFUN		;Find out where data starts (past this word)
	ADD T2,Q1		;Now make it absolute
	MOVE T1,Q3		;[7.1090] Assume we can BLT this many
	CAILE T1,<C%MUDA-CLDATA+.MHUDA> ;[7.1090] Too many words?
	MOVEI T1,<C%MUDA-CLDATA+.MHUDA> ;[7.1090] Yes, only do this many
	CALLX (MSEC1,XBLTAT)	;(T1,T2,T3/T1,T2,T3) Blast data to CLUDGR fork's page
	SKIPN Q1,.CLFLI(Q1)	;[7.1090] Get next SCA buffer in chain
	IFSKP.			;[7.1090] If another buffer...
	  SUBI Q3,<C%MUDA-CLDATA+.MHUDA> ;[7.1090] Account for the words we just BLTed
	  JRST CLFRS1		;[7.1090] Do next buffer
	ENDIF.			;[7.1090]
	RET			;All buffers reassembled
	SUBTTL CLUDGR Fork -- CLFWAT (Scheduler test to wait for action)

;CLFWAT - Scheduler test used by the CLUDGR fork. The CLUDGR fork will
;will use this to wait for something to do.
;
; Called with:
;	no arguments
;	MDISMS to CLFWAT
;
; Returns:
;	+1 - Go back to sleep, nothing to do
;	+2 - CLUFLG was set, time to check out the action

	RESCD			;Like all good scheduler tests

CLFWAT:	SKIPN CLUFLG		;Is it time to process goodies?
	RET			;No, too early to go to work
	RETSKP			;Respond to alarm clock
	SUBTTL CLUDGR Fork -- ZERDAT (Zero out data area)
;ZERDAT - Routine called to zero out the data area for CLUDGR fork.
;
; Called with:
;	no arguments
;	CALL ZERDAT
;
; Returns:
;	+1 - Always, with CLFSCR page and CLFREA page all zeroes

	XSWAPCD			;Called at process level

ZERDAT:	SETZM CLFSCR		;Zero out scratch area
	MOVE T1,[CLFSCR,,CLFSCR+1] ;Source and
	BLT T1,CLFSCR+777	;destination of overlap
	SETZM CLFREA		;Now do reassembly page
	MOVE T1,[CLFREA,,CLFREA+1] ;Start here and
	BLT T1,CLFREA+777	;do up to here
	RET			;All zeroed
	SUBTTL CLUDGR Fork -- CLFSND (Routine to send results)
;CLFSND - This routine is the responder. It sends the data obtained
;by the function and put into CLFSCR back to the requestor on the
;remote system.
;
; Call with:
;	T1/ number of words in CLFSCR to be sent and
;	CLFSCR setup
;	CALL CLFSND
;
; Or call with:
;	no arguments
;	CALL CLxSND (where 0<x<4 and X is the number of words to send
;
; Returns:
;	+1 - Always, data sent. However, this routine may block
;	     while several attempts to make the send are tried.
;	     If the send fails MAXTRY times, we crash.

	XSWAPCD			;Fork fun

CL1SND:	MOVEI T1,1		;Send over 1 word
	JRST CLFSND		;Common code

CL2SND:	MOVEI T1,2		;Send over 2 words
	JRST CLFSND		;Join common code

CL3SND:	MOVEI T1,3		;Send over 3 words
	JRST CLFSND		;Join common code

CLFSND:	SAVEQ			;[7.1090] Save what we use
	STKVAR <TRIES,WRDS,BUFCHN,NEXT,RETBUF> ;Temp data storage
	MOVEM T1,WRDS		;Save the number of words
	MOVEI T1,MAXTRY		;Max number of tries
	MOVEM T1,TRIES		;Stash it for now
CLFSN1:	HRR T2,WRDS		;Get count of words to move
	HRLI T2,<CLDATA-.MHUDA>	;Start putting data in at this word
	XMOVEI T1,CLFSCR	;Here's the data
	NOINT			;To satisfy SC.BRK
	CALL SC.BRK		;(T1,T2/T1,T2,T3) Put stuff in SCA message buffers
	IFNSK.			;If we failed,
	  SOSGE TRIES		;See if we failed too much
	  BUG. (HLT,CLOUTB,CLUFRK,SOFT,<System out of SCA buffers>,,<

Cause:	The CLUDGR fork was trying to send a response to a remote
	system. However, it could not obtain the SCA bufferage to
	do so.

Action:	Find out who is eating up the SCA buffers.
>)				;We've had enough
	  OKINT			;Undo NOINT
	  MOVEI T1,WAIT		;Sleep a bit
	  DISMS%		;Maybe buffers will come back
	  JRST CLFSN1		;Try it again
	ENDIF.
	OKINT			;All set now
	ADDM T2,CLUBUF		;Add the buffers in use by CLUDGR
	MOVEM T1,BUFCHN		;Save SCA buffer chain
	MOVEM T3,RETBUF		;Routine to return the buffers
	MOVX T2,CL%REQ		;Say this is a response
	ANDCAM T2,FLAGS		;By clearing this bit
	BLCAL. (FILLIN,<T1,FLAGS,REQID,CODE,FRK,CINODE,REMUSR,WRDS>) ;[7.1090]
				;[7.1090] Fill in SCA buffer chain
	MOVEI T1,MAXTRY		;Max number of tries
	MOVEM T1,TRIES		;Stash it for now
	MOVE Q1,WRDS		;[7.1090] Get word count
CLFSN2:	MOVE T1,BUFCHN		;Get first buffer in chain
	MOVE T2,.PKFLI(T1)	;Get next SCA buffer in chain
	MOVEM T2,NEXT		;Save it to be sent later
	MOVE T2,REMCID		;Get connect ID
	MOVE Q2,Q1		;[7.1090] Get word count
	ADDI Q2,CLDATA		;[7.1090] Figure in the header
	CAILE Q2,C%MUDA		;[7.1090] Good size?
	MOVEI Q2,C%MUDA		;[7.1090] No, too big, so send maximum
	BLCAL. (<XENT SC.SMG>,<T2,[F.RTB+F.SPM],Q2,T1,[CLUPRI],[0],[0]>) ;[7.1090]
	IFNSK.			;Send failed
	  CAIE T1,SCSNEC	;Was it due to insufficient credit?
	  IFSKP.		;Yes
	    SOSGE TRIES		;Add this failure. Have we tried enough?
	    CALL CLFFAL		;(/) Yes, CRASH!
	  ELSE.			;Else node probably went away
	    JRST PNTCHN		;Punt the entire chain
	  ENDIF.
	  MOVEI T1,WAIT		;Sleep for a bit
	  DISMS%
	  JRST CLFSN2		;And try to send again
	ENDIF.
	SKIPN T2,NEXT		;Get next SCA buffer
	IFSKP.			;If there are more to send
	  MOVEM T2,BUFCHN	;Put it where it will be picked up
	  SUBI Q1,<C%MUDA-CLDATA+.MHUDA> ;[7.1090] Account for the words we just sent
	  JRST CLFSN2		;And send it
	ENDIF.
	RET			;All done sending
;Here when send failed somehow. We are now going to give back
;the rest of the SCA buffers.
PNTCHN:	MOVE T1,BUFCHN		;Get buffer back
	SOS CLUBUF		;Discount this buffer
	CALLX (MSEC1,SC.RBF)	;(T1/) Now return it
	SKIPN T1,NEXT		;Was there more?
	RET			;No more, go back
	MOVEM T1,BUFCHN		;Put it here
	MOVE T1,.PKFLI(T1)	;Get the next one in line
	MOVEM T1,NEXT		;And stash it here
	JRST PNTCHN		;And punt the rest of the chain

	ENDSV.
	SUBTTL End of CLUFRK

	ENDTV.

	END