	.TITLE BREAK - detects and deletes detached LOGINOUT processes
	.ENABLE DEBUG
	.IDENT /01/
;	+++
;
;	FUNCTIONAL DESCRIPTION:
;		This program scans through the current processes on
;		a system looking for any that are (1) disconnected
;		and (2) running LOGINOUT.  These processes are then
;		deleted.
;
;	IMPLICIT INPUTS:
;		$GETJPI data from system image
;
;	IMPLICIT OUTPUTS:
;		none
;
;	COMPLETION STATUS:
;
;		SS$_NORMAL	Normal Successful completion
;		(others are possible in error conditions)
;
;	SIDE EFFECTS:
;		Deletes processes.
;
;
;	AUTHOR, DATE;TIME of CREATION
;		Joel M Snyder, 15-May-1985
;
;
;	---
.PAGE
;	+++
;			FURTHER INFORMATION
;
;	This program was written in response to a problem generated
;	by VAX/VMS V4.0 "disconnectable" terminals.  Any disconnectable
;	terminal will generate up to MAXPROCNT jobs, disconnected,
;	and running LOGINOUT, if someone presses the BREAK key enough
;	times.  While user education will help this problem, this program
;	provides a means of self-defence for VAX systems seeing this
;	behavior.
;
;	To use, put a $ RUN/DETACH/PRIV=WORLD BREAK in your SYSTARTUP.COM.
;
.page
;	system call macros
	$JPIDEF
	$DVIDEF

;	some miscellaneous constants
	PHYSICAL_DEVICE_LENGTH = 64		; maximum size of a device
	WILDCARD = -1				; wildcard $GETJPI starter
	IMAGE_LENGTH = 80			; length of an image name
	TERMINAL_LENGTH=8			; size of a VTA term name
	PID_LENGTH = 4				; size of a PID in bytes

.PAGE		
;	impure storage locations
	.PSECT RWDATA,WRT,NOEXE,NOSHR,LONG

PID:	.long 0					; context for $GETJPI

;+++ $GETDVI LIST
dvilist:.word PHYSICAL_DEVICE_LENGTH		; get the physical
	.word dvi$_tt_phydevnam			; device for a VTA device
	.address ptty
	.address ptty_len
;
	.long 0					; END OF $GETDVI list
;--- END $GETDVI LIST

;+++ $GETJPI LIST
list:	.word IMAGE_LENGTH			; currently running 
	.word jpi$_imagname			; image for this process
	.address image				; pointer to data
	.address image_len			; length of image name
;
	.word TERMINAL_LENGTH			; terminal name for this
	.word jpi$_terminal			; process, expressed as
	.address tty				; a VTAxxx string normally.
	.address tty_len			; pointer and length
;
	.word PID_LENGTH			; PID for this process,
	.word jpi$_pid				; expressed as a longword
	.address rpid				; integer
	.address rpid_len			; pointer and length
;
	.long 0					; end of list.
;--- END $GETJPI LIST

; The following information is order specific.  Do not
; change the order of items in this data structure.
image_len:	.long 0				; length of image name
image_ptr:	.address image			; pointer to image name
image:		.blkb IMAGE_LENGTH		; bytes for image name

logimage_cnt:	.word 8				; size of word "LOGINOUT"
logimage:	.ascii 'LOGINOUT'		; string to MATCHC on.

tty_len:	.long 0				; length of VT
tty_ptr:	.address tty			; pointer to terminal name
tty:		.blkb  TERMINAL_LENGTH		; bytes for terminal name

rpid:		.blkb PID_LENGTH		; real pid
rpid_len:	.long 0				; and length 

ptty:		.blkb PHYSICAL_DEVICE_LENGTH	; bytes for physical dev
ptty_len:	.blkl 1				; and length

timetowait:	.ascid /0 00:01:00.00/		; time to wait
binarytime:	.blkq 1				; between scans. 

.PAGE
;
; Executable Code
;
	.PSECT 	CODE,EXE,RD,NOWRT
;
break:	.word 0					; entry mask
;+++
; initialize the $GETJPI by moving a -1 into the PID value
; that is used for calling.
;---
init:	movl	#WILDCARD,PID			; init $GETJPI entry mask

;+++
; do the $GETJPI (waiting, as is appropriate in V4). See if there
; are no more processes. If no more available, then goto the wait
; loop. If there is any other error, then quit (exiting R0).
; Assuming that there is a process and there is no error, find
; if the length of the tty is 0. If the TTY length is zero, then
; this process doesn't have an associated terminal and thus is
; not a candidate for deleting (ex, NULL, JOB_CONTROL, etc).
;---
get:	$getjpiw_s	pidadr=pid,-		; PID
		  	itmlst=list		; get data from $GETJPI
	cmpw	r0,#SS$_NOMOREPROC		; if no more processes,
	beql	wait				; then goto wait loop
	blbc	r0,get				; if an error, then
	cmpw	tty_len,#0			; quit. If no tty, then
	beql	get				; get another process

;+++
; get the physical device name for the virtual terminal for
; this process. Quit on error here. If the physical length
; is zero, then this terminal is disconnected.  If not, return
; to the main GET: loop.  Then check the image name. If the
; image name contains LOGINOUT, then this is a disconnected
; process running LOGINOUT.
;---
dvi:	$getdvi_s	devnam=tty_len,-	; Char Descript of TTY
			itmlst=dvilist		; get physical device 
	blbc	r0,get				; if an error, then ignore
	cmpl	ptty_len,#0			; if physical size .NE. 0,
	bnequ	get				; then get another user
	matchc	logimage_cnt,logimage,image_len,image
	cmpl	r1,#logimage			; if .NOT. running LOGINOUT,
	beqlu	get				; then get another user.

kill:	$delprc_s	pidadr=rpid		; delete this user and
	brw	get				; continue scan.

;+++
; enter this section of code on error. Exit immediately.
; see next block comment for information on turning BREAK
; into a subroutine in your standard idle job killer program.
;---
;quit:	$exit_s	code=R0				; on error, go here.

;+++
; enter this segment of code between passes through the $GETJPI
; table.  Convert the time in TIMETOWAIT ( an ASCII delta) to
; a binary absolute time.  Schedule a wakeup for that time, and
; hibernate until the time passes.  Upon waking up, go back to
; the initialization code and start again.  To turn this program
; into a subroutine, insert a MOVZWL #SS$_NORMAL, R0  and a RSB
; at WAIT instead of the timing information. Then, put a RSB at
; QUIT instead of the $EXIT. Fix the register mask (I think that
; the MATCHC uses R0->R5) and call BREAK, testing R0 for SS$_NORMAL.
;---
wait:	$bintim_s timbuf=timetowait,timadr=binarytime
	$schdwk_s daytim=binarytime		; convert time to wait,
	$hiber_s				; $schd and $hiber
	brw	init				; upon waking, re-init

	.end break				; of executable code
