1	!****************************************************************
	! IDENTIFICATION DIVISION.

	%TITLE 		"WATCHDOG - Watchdog timer"
	! AUTHOR.		Thomas Stegman
	! INSTALLATION.		Federal Land Bank of Wichita.
	! DATE-WRITTEN.		08/30/84
	! DATE-COMPILED.	08/31/84
	! VERSION.		1.2
	! DATE-MODIFIED.        06/24/85
	! MODIFICATION-HISTORY.
	!
	!  Date      Who	Ver.	Comments
	!---------------------------------------------------------------------
	! 08/31/84  T.Stegman	1.1	Original write

        ! 06/24/85  S.Cowart    1.2     Modify to use logical WATCHDOG_INTERVAL
	!				instead of hard-coded value in program
	!				to determine how long terminal may be
	!				inactive before being logged off.
	!
	!				Changed program to use a different
	!				variable (SLEEP_INTERVAL) from
	!				inactive variable (INTERVAL) to
	!				determine how long to sleep between 
	!				checks for inactive processes.
	!
	! 07/03/85  S.Cowart    1.3     Corrected problem with operator term
	!                               (OPA0:) being logged off.
	!
	! 10/18/85  S.Cowart    1.4     Minor corrections to run under VMS V4
	!                               and fix to prevent blow off when user
	!                               logoff occurs at time that Watchdog
	!                               tries to broadcast logoff message and
	!                               kill process.
	!
	! 12/18/85  S.Cowart	1.5	Added check for cputime or bufio
	!				less than or greater than previous
	!				value.  When using EZLOG to change
	!				project (CP nnnn), the cputime and
	!				bufio are reset to zero.  Watchdog
	!				was logging people off because of
	!				the reset values.
	!
	! 03/03/86  S.Cowart	1.6	Added 1 second pause after sending
	!				logoff message to terminal and FORCEX
	!				in order to allow service to complete
	!				before deleting process.  Changed
	!				system service calls to V4, i.e.
	!				BRKTHRU instead of BRDCST.  Use
	!				GETJPI process_index for index into
	!				arrays; if terminal has operator
	!				status (REPLY/ENABLE has been done
	!				from that terminal) then User will
	!				not be logged off.  Issue warning
	!				5 minutes before user is to be logged
	!				off.
	!
	! 04/21/86  S.Cowart	1.7	Changed condition code parameter
	!				of SYS$FORCEX to SS$_NORMAL to stop
	!				NOMSG messages from being displayed
	!				on logged out terminals.
	!
	! 01/27/87  S.Cowart	1.8	Added check for OPA0:.  Whoever is
	!				logged in at OPA0: will not be logged
	!				off.  Deleted call to LIB$SIGNAL; this
	!				was causing WATCHDOG to abort with a
	!				dump.
	!
	! 03/24/87  S.Cowart	1.9	Do not warn users of TPU or SPSSG of
	!				impending logoff in 5 minutes.  Because
	!				these two utilities process the
	!				incoming broadcast messages and stow
	!				them, it may still be using cpu when
	!				Watchdog takes another snapshot of the
	!				process to compare against next time. 
	!				This tends to happen when the system is
	!				is loaded down and running slow.
	!
	! 04/13/87  N.Schroeder 1.10	Vary the logout time interval depending
	!				on the number of users on the system.
	!				There are three logicals which contain
	!				the lower, mid, and upper intervals,
	!				and two logicals which determine the
	!				break points for the number of users
	!				on the system. They interact as follows:
	!
	!		WATCHDOG_UPPER_INTERVAL   !
	!					  !
	!					--+--   WATCHDOG_UPPER_USERS
	!					  !
	!		WATCHDOG_MID_INTERVAL     !
	!					  !
	!					--+--   WATCHDOG_LOWER_USERS
	!					  !
	!		WATCHDOG_LOWER_INTERVAL   !
	!
        ! 04/15/87  N.Schroeder		Remove some test code that had been
	!				inadvertently left in last time.
	!
	!	COMMENT SECTION.
	!
	! WATCHDOG  is a program to automatically log off user terminals
	! at which there is no activity.  The time period is set by the 
	! system logical WATCHDOG_INTERVAL.  We are currently using a value
	! of "15" (15 minutes) for WATCHDOG_INTERVAL.  
	! WATCHDOG will sleep for the sleep_interval, then wake up
	! and check for processes which have been inactive for
	! greater than or equal to the WATCHDOG_INTERVAL.  Currently, the
	! sleep_interval is 5 minutes.  The value of WATCHDOG_INTERVAL is
	! retrieved every time WATCHDOG wakes up.  If the value of the
	! logical has not changed since last time, then validation of the
	! the logical string is bypassed and INTERVAL retains its previous
	! value.  If the string has changed (or it is the first time thru),
	! then the string is validated that it is numerics only.  If the
	! string contains non-numeric characters, or the system logical
	! does not exist, then INTERVAL is set to a default inactive value
	! (DEFAULT_INTERVAL currently is 15 minutes).  If WATCHDOG_INTERVAL 
        ! is set for a period longer than 60 minutes, it will default to 
        ! 60 minutes.  ALSO, IF THERE IS AN ERROR WITH TRYING TO RETRIEVE
	! THE WATCHDOG_INTERVAL VALUE, THEN AN ERROR MESSAGE WILL DISPLAY
	! AT THE OPERATOR CONSOLE EVERY TIME WATCHDOG WAKES UP UNTIL THE
	! PROBLEM IS RESOLVED.
	!
	! WATCHDOG looks at the list of active processes in the system
	! and determines which need to be logged off because of inactivity.
	! Processes that are NOT associated with a terminal are left alone.
	! Sub-processes as well main processes are examined.  Information
	! on each process is kept in a set of tables in order to compare
	! changes in cpu time, buffered I/O, and the length of time that
	! the process has been inactive.

	%page
	!****************************************************************
	! ENVIRONMENT DIVISION.

	! CONFIGURATION SECTION.
	! OBJECT-COMPUTER.		DEC VAX 11780
	! SOURCE-COMPUTER.		DEC VAX 11780
	! LANGUAGE-TYPE.		VAX-11 BASIC
	! PROGRAM-TYPE.			MAIN
	! SPECIAL-NAMES.

	%page
	!****************************************************************
	! DATA DIVISION.

	OPTION TYPE = EXPLICIT

	! WORKING-STORAGE SECTION.

	map (jobinfo)		word uic_number			&
				,word uic_group			&
				,string username = 12%		&
				,string term = 8%		&
				,long term_length		&
				,long cpu_time			&
				,long buf_io			&
				,long proc_count		&
				,long job_proc_count		&
				,long owner_pid			&
				,byte pid_index			&
				,byte pid_seq			&
				,word pid_cluster_id		&
				,string process_name = 15%	&
				,long process_name_length	&
				,string image_name = 64		&
				,long image_name_length		&

	map (jobinfo)		long uic			&
				,string fill = 44		&
				,long pid			&

	map (range)		long low_addr,			&
				long high_addr			&

	! set up item list for get process info sys call

	record item_list
				word buff_length1
				word item_code1
				long buff_addr1
				long ret_length_addr1
				word buff_length2
				word item_code2
				long buff_addr2
				long ret_length_addr2
				word buff_length3
				word item_code3
				long buff_addr3
				long ret_length_addr3
				word buff_length4
				word item_code4
				long buff_addr4
				long ret_length_addr4
				word buff_length5
				word item_code5
				long buff_addr5
				long ret_length_addr5
				word buff_length6
				word item_code6
				long buff_addr6
				long ret_length_addr6
				word buff_length7
				word item_code7
				long buff_addr7
				long ret_length_addr7
				word buff_length8
				word item_code8
				long buff_addr8
				long ret_length_addr8
				word buff_length9
				word item_code9
				long buff_addr9
				long ret_length_addr9
				word buff_length10
				word item_code10
				long buff_addr10
				long ret_length_addr10
				word buff_length11
				word item_code11
				long buff_addr11
				long ret_length_addr11
				word buff_length12
				word item_code12
				long buff_addr12
				long ret_length_addr12
				long list_terminator
	end record item_list

	declare item_list items

	map (interval_info)	string interval_string = 2	&
				,string lower_user_string = 2	&
				,string upper_user_string = 2	&
				,word interval_string_length	&
				,string old_interval_string = 2	&
				,string old_upper_string = 2	&
				,string old_lower_string = 2	&
				,string interval_logical = 23	&

	! set up item list for translate logical sys call

	record logical_item_list
		       		word log_buff_length1
				word log_item_code1
				long log_buff_addr1
				long log_ret_length_addr1
				long log_list_terminator
	end record logical_item_list

	declare logical_item_list log_items

	map (brkthru_info)	word sendtype			&
				,long carr_ctrl			&
				,long brkthru_flags		&
				,long brkthru_timeout		&
				,word compl_status		&
				,word succss_sends		&
				,word time_outs			&
				,word nobrdcsts			&

	! set up item list for getdvi sys call

	record dvi_item_list
		       		word dvi_buff_length1
				word dvi_item_code1
				long dvi_buff_addr1
				long dvi_ret_length_addr1
				long dvi_list_terminator
	end record dvi_item_list

	declare dvi_item_list dvi_items

	map (getdvi_info)	long oper_term			&
				,word dvi_iosb1			&
				,word dvi_iosb2			&
				,word dvi_iosb3			&
				,word dvi_iosb4			&

	external word		sys$gw_ijobcnt			&

	external long function 	sys$getjpiw			&
				,sys$getdviw			&
				,sys$brkthruw			&
				,sys$delprc			&
				,sys$forcex			&
				,sys$purgws			&
				,sys$waitfr			&
				,lib$stop			&
				,lib$signal			&
				,lib$get_ef			&
				,sys$trnlnm			&
                         
	external long constant					&
			jpi$_username				&
			,jpi$_uic				&
			,jpi$_terminal				&
			,jpi$_cputim				&
			,jpi$_bufio				&
			,jpi$_prccnt				&
			,jpi$_imagname				&
			,jpi$_jobprccnt				&
			,jpi$_owner				&
			,jpi$_pid				&
			,jpi$_prcnam				&
			,jpi$_proc_index			&
			,lnm$_string				&
			,ss$_nomoreproc				&
			,ss$_suspended				&
			,ss$_normal				&
			,ss$_devoffline				&
			,dvi$_opr				&
			,brk$c_device				&
			,brk$m_screen				&
			,brk$m_bottom				&

	declare long	sys_status				&
			,sys_status1				&
			,context_pid				&
			,cur_pid				&
			,process_id_index			&
			,interval				&
			,users_on_system			&
			,lower_user_limit			&
			,upper_user_limit			&
			,event_flag				&

	declare word	user_ok					&
			,i					&
			,j					&
			,k					&
			,upper_bound				&
			,sleep_interval_secs			&

	declare string	message					&
			,exe_image				&


	declare word constant	system_is_up = -1%		&
				,maxuser = 256%			&
				,true = -1%			&
				,false = 0%			&
				,logical_tbl_search_mask = 6%	&
				,one_hour = 60%			&
				,sleep_interval_mins = 5%	&
				,negative_one = -1%		&

	! System logical for the time interval (WATCHDOG_INTERVAL) and
        ! default interval if problem with retrieving WATCHDOG_INTERVAL value.

	declare string constant	upper_interval  = "WATCHDOG_UPPER_INTERVAL" &
				,mid_interval   = "WATCHDOG_MID_INTERVAL"   &
				,lower_interval = "WATCHDOG_LOWER_INTERVAL" &
				,upper_users    = "WATCHDOG_UPPER_USERS"    &
				,lower_users    = "WATCHDOG_LOWER_USERS" &
				,digits = "0123456789"		&
				,default_interval = "15"	&
				,operator_terminal = "OPA0:"	&
				,system_logical_table = "LNM$SYSTEM"	&
				,right_bracket = "]"		&
				,semi_colon = ";"		&

	dimension long	cputim(maxuser),bufio(maxuser),seq(maxuser),	&
			inactiv(maxuser),uicsave(maxuser)		&

	dimension byte  warning_flag(maxuser)
	%page
	!****************************************************************
	! PROCEDURE DIVISION.

100

 P_100_Program_Initialization:

	on error goto error_routine

	! Init record block for call to get user process information

	items::buff_length1 = 12
	items::item_code1 = jpi$_username
	items::buff_addr1 = loc(username)
	items::buff_length2 = 4
	items::item_code2 = jpi$_uic
	items::buff_addr2 = loc(uic_number)
	items::buff_length3 = 8
	items::item_code3 = jpi$_terminal
	items::buff_addr3 = loc(term)
	items::ret_length_addr3 = loc(term_length)
	items::buff_length4 = 4
	items::item_code4 = jpi$_cputim
	items::buff_addr4 = loc(cpu_time)
	items::buff_length5 = 4
	items::item_code5 = jpi$_bufio
	items::buff_addr5 = loc(buf_io)
	items::buff_length6 = 4
	items::item_code6 = jpi$_prccnt
	items::buff_addr6 = loc(proc_count)
	items::buff_length7 = 4
	items::item_code7 = jpi$_jobprccnt
	items::buff_addr7 = loc(job_proc_count)
	items::buff_length8 = 4
	items::item_code8 = jpi$_owner
	items::buff_addr8 = loc(owner_pid)
	items::buff_length9 = 4
	items::item_code9 = jpi$_pid
	items::buff_addr9 = loc(pid_index)
	items::buff_length10 = 15
	items::item_code10 = jpi$_prcnam
	items::buff_addr10 = loc(process_name)
	items::ret_length_addr10 = loc(process_name_length)
	items::buff_length11 = 64
	items::item_code11 = jpi$_imagname
	items::buff_addr11 = loc(image_name)
	items::ret_length_addr11 = loc(image_name_length)
	items::buff_length12 = 4
	items::item_code12 = jpi$_proc_index
	items::buff_addr12 = loc(process_id_index)
	items::list_terminator = 0%

	log_items::log_buff_length1 = 2%
	log_items::log_item_code1 = lnm$_string
	log_items::log_buff_addr1 = loc(interval_string)
	log_items::log_ret_length_addr1 = loc(interval_string_length)
	log_items::log_list_terminator = 0%

	sys_status = lib$get_ef(event_flag)

	sendtype = brk$c_device
	brkthru_flags = brk$m_screen or brk$m_bottom
	carr_ctrl = 32%
	brkthru_timeout = 5%

	dvi_items::dvi_buff_length1 = 4%
	dvi_items::dvi_item_code1 = dvi$_opr
	dvi_items::dvi_buff_addr1 = loc(oper_term)
	dvi_items::dvi_list_terminator = 0%

	old_interval_string = "99"

	! Convert sleep interval minutes to equivalent seconds

	sleep_interval_secs = sleep_interval_mins * 60

	if sys_status and 1% = 0%
	then
		goto P_32760_Error_exit
	end if

	gosub P_900_Get_Users_and_Intervals ! Obtain current logical values 

	high_addr = X"7FFFFFFF"L

200

 P_200_Main_Program_logic:

	sys_status = sys$purgws(low_addr)

	if sys_status and 1% = 0%
	then
		goto P_32760_Error_exit
	end if

	while system_is_up

		context_pid = -1%
		cur_pid = -1%
		sys_status = ss$_normal


 Step_thru_processes:

		until sys_status = ss$_nomoreproc

			user_ok = false

			! Get user process information

			cur_pid = context_pid
			gosub P_1100_Get_user_info
			context_pid = cur_pid

			iterate if sys_status = ss$_nomoreproc or	&
				   sys_status = ss$_suspended

			! If this guy owns a subprocess we will leave him alone
			! for now and check him when we check the subprocess.

			iterate if proc_count > 0

			gosub p_1000_check_user_status
			iterate if user_ok

			! If there is a terminal attached that has received 
			! the 5 minute warning, then we have a main 
			! process that needs to be deleted.

		       if term_length > 0 
			then
				gosub P_1200_Delete_user
				iterate
			end if

			! This is a subprocess, so we must check all other 
			! processes in the job; begin by checking this guy's
			! owner process.

			until term_length > 0
				cur_pid = owner_pid
				user_ok = false
				gosub P_1100_Get_user_info
				gosub P_1000_Check_user_status
				iterate Step_thru_processes if user_ok
			next

			gosub P_1200_Delete_user
			iterate

		! Get next user info
	
		next


		! Sleep_interval_secs is number of seconds between sweeps
		! for inactive processes

		sleep (sleep_interval_secs)
                gosub P_900_Get_Users_and_Intervals ! See if anything changed
	next

900

 P_900_Get_Users_and_Intervals:

	! Check WATCHDOG_UPPER_USERS and WATCHDOG_LOWER_USERS to see if they
	! have changed. If so, validate them. Then see how many users are on
	! the system to determine if the interval should be in the upper, mid,
	! or lower range. Then check that logical to see if it has changed.
	! If so, validate it. The result is the new current time interval.

	gosub P_2100_get_upper_users
	gosub P_2200_get_lower_users

	users_on_system = sys$gw_ijobcnt
	interval_logical = mid_interval
	interval_logical = lower_interval if users_on_system < lower_user_limit
	interval_logical = upper_interval if users_on_system > upper_user_limit

	gosub P_2300_get_interval

	return

1000

 P_1000_Check_user_status:

		! If the sequence number changed, then this is a new user
		! with this pid, so leave him alone.

		if seq(process_id_index) <> pid_seq
		then
			seq(process_id_index) = pid_seq  ! Save sequence number
			warning_flag(process_id_index) = 0  ! Clear warning flag

			! Save number of minutes till next check by watchdog

			inactiv(process_id_index) = sleep_interval_mins
			gosub P_1300_Save_user_info
			warning_flag(process_id_index) = 0
			user_ok = true
			return
		end if


		! If this process has no terminal and no owner process,
		! then it must be detached so leave it alone.

		if term_length = 0 and owner_pid = 0
		then
			warning_flag(process_id_index) = 0
			user_ok = true
			return
		end if

		! If this process is logged in at OPA0: then leave alone.

		if term = operator_terminal
		then
			warning_flag(process_id_index) = 0
			user_ok = true
			return
		end if

		oper_term = 0%
		if term_length > 0%
		then
			sys_status = sys$getdviw(,,term,dvi_items by ref,  &
				dvi_iosb1 by ref,,,)
			if sys_status <> ss$_normal
			then
				warning_flag(process_id_index) = 0
				user_ok = true
				return
			end if
			sys_status = ss$_normal
		end if

		! An operator terminal is immune from Watchdog logout.

		if oper_term = 1%
		  then 
			warning_flag(process_id_index) = 0
			user_ok = true
			return
		end if

		! If process is running an image then found out image name
		if image_name_length <> 0%
		then
			! Extract image name and place in exe_image variable
			exe_image = seg$(image_name,1%,image_name_length)

			! Set j to length of image name in exe_image
			j = len(exe_image)

			! Start from the end of the string and go towards the beginning
			! looking for a right bracket ("]")
			for k = j step negative_one until pos(exe_image,right_bracket,k) > 0%
			next k

			! Extract image name starting from the next position to the
			! right of the rightmost "]" in exe_image and reassign to 
			! exe_image.  This will strip off device and directory name
			! parts of the image name (since it is a VAX standard file 
			! specification.
			exe_image = seg$(exe_image,k+1%,len(exe_image))

			! Reset j to new length of image name
			j = len(exe_image)

			if pos(exe_image,semi_colon,1%) > 0%
			then
				! Now start from the end as above and look for the rightmost
				! semi-colon in the image name.  When it is found then drop the
				! version number part of the image file name leaving the
				! file name and extension parts.
				for k = j step negative_one until pos(exe_image,semi_colon,k) > 0%
				next k
				exe_image = seg$(exe_image,1%,k-1%)
			end if
		end if

		! If the cpu time has increased by at least 50 ms or
		! any buffered i/o has occurred or if cpu time or bufio
		! is less than previous or uic has changed, (EZLOG CP function
		! entered) then leave him alone.

		if cpu_time => cputim(process_id_index) + 5 or		&
			   buf_io > bufio(process_id_index) or		&
			cpu_time < cputim(process_id_index) or		&
			buf_io < bufio(process_id_index) or		&
			uic <> uicsave(process_id_index)
		then
			gosub P_1300_Save_user_info
			warning_flag(process_id_index) = 0
			inactiv(process_id_index) = sleep_interval_mins
			user_ok = true
		else
			! If accum inactive time is less than the
			! WATCHDOG_INTERVAL value, then add the
			! sleep_interval_mins to the inactive accum for the
			! process

			if warning_flag(process_id_index) = 0
			then
			       inactiv(process_id_index) =		&
					inactiv(process_id_index)	&
			       + sleep_interval_mins
				if inactiv(process_id_index) >= interval
				then

		      	! Send warning message to user and set warning flag

				    warning_flag(process_id_index) = 1
				    if exe_image <> "TPU.EXE" and exe_image <> "SPSSGRAPHICS.EXE"
				    then

					message = time$(0) + " " + username + " will be logged off in " &
						+ num1$(sleep_interval_mins) + " minutes because of inactivity."+ BEL + BEL

 					sys_status = sys$brkthruw(,message, 	&
 						term,sendtype by value, &
 						compl_status by ref,carr_ctrl by value,	&
 						brkthru_flags by value,,	&
 						brkthru_timeout	by value,,)
 
					sys_status = ss$_normal

				! Retrieve current process values, since sending the warning message increments BUFIO.
				! Obtain the job information of the process.

					sys_status = sys$getjpiw(event_flag by value, pid,, items,,,)
					sys_status = ss$_normal
					gosub P_1300_Save_user_info
				    end if
				end if
			user_ok = true
			end if
		end if

		return

1100

 P_1100_Get_user_info:

	! Obtain the job information of the process.

	sys_status = sys$getjpiw(event_flag by value, cur_pid,, items,,,)

	if (sys_status and 1%) = 0% and sys_status <> ss$_nomoreproc &
		and sys_status <> ss$_suspended
	then
		goto P_32760_Error_exit
	end if

	return if sys_status = ss$_nomoreproc or sys_status = ss$_suspended

	if sys_status and 1% = 0%
	then
		goto P_32760_Error_exit
	end if

	! This is to add a colon to Virtual terminals (VTAnnn) which have 
	! gone over VTA999.  VMS V4.1 has a bug which drops the colon on
	! virtual terminal numbers over VTA999.

	if pos(term,":",1%) = 0% and term_length > 0
	then
		term = seg$(term,1%,term_length) + ":"
		term_length = term_length + 1%
	else
		! This is to pad the terminal name with blanks.
		term = seg$(term,1%,term_length)
	end if

	return

1200

 P_1200_Delete_user:

 	! Send logoff message to user

	message = time$(0) + " " + term + " inactive for " +	&
	   num1$(interval) + " minutes - " + username + " logged out." + BEL

 	sys_status = sys$brkthruw(,message, 	&
 		term,sendtype by value, &
 		compl_status by ref,carr_ctrl by value,	&
 		brkthru_flags by value,,	&
 		brkthru_timeout	by value,,)

	sleep 1%

	sys_status = 0

	if image_name_length > 0
	then
 		sys_status = sys$forcex(pid,,ss$_normal by value)

		sleep 1%

		sys_status = 0
	end if

 	sys_status = sys$delprc(pid,)

	sys_status = 0

	return

1300

 P_1300_Save_user_info:

	! Save cpu time and buffered i/o on this user

	cputim(process_id_index) = cpu_time
	bufio(process_id_index) = buf_io
	uicsave(process_id_index) = uic
	return

2100

 P_2100_get_upper_users:

	sys_status = sys$trnlnm(,system_logical_table,upper_users,,log_items)
	upper_user_string = interval_string

		select (sys_status)

		  case (ss$_normal)

		  ! If previous string value = current string value then
		  ! no validation is necessary.

		  if upper_user_string <> old_upper_string
		    then

		      ! Validate that string is only numeric characters, no
		      ! spaces, special, or alpha chars. If any problems with
		      ! string, assign in a default string value.

			upper_bound = interval_string_length
			for i = 1% to upper_bound
			if pos(digits,seg$(upper_user_string,i,i),1%) = 0%
			  then
			  	i = upper_bound + 1%
			   	upper_user_string = "99"
				message = BEL + BEL + time$(0) +	&
				"*** WATCHDOG_UPPER_USERS" 		&
				+ " logcl has non-nums." + 		&
				" Deflting to 99 users."	
				sys_status = sys$brkthruw(,message, 	&
				    	operator_terminal,sendtype by value, &
					compl_status by ref,carr_ctrl by value,	&
					brkthru_flags by value,,	&
					brkthru_timeout	by value,,)

				sys_status = 0
			  end if
			next i

		  end if

		  old_upper_string = upper_user_string 		&
			if upper_user_string <> "99"

		  upper_user_limit = val%(seg$(upper_user_string,1%,	&
				interval_string_length))

		  ! If not normal return from logical translation,
		  ! then use default interval value

		  case else
			upper_user_limit = 99

			message = BEL + BEL + time$(0) +		&
			"*** WATCHDOG_UPPER_USERS"			&
			+ " logcl transl err. " +			&
			"Deflting to 99 users."

			sys_status = sys$brkthruw(,message, 	&
				operator_terminal,sendtype by value, &
				compl_status by ref,carr_ctrl by value,	&
				brkthru_flags by value,,	&
    				brkthru_timeout	by value,,)

			sys_status = 0

		end select

                return

2200

 P_2200_get_lower_users:

	sys_status = sys$trnlnm(,system_logical_table,lower_users,,log_items)
	lower_user_string = interval_string

		select (sys_status)

		  case (ss$_normal)

		  ! If previous string value = current string value then
		  ! no validation is necessary.

		  if lower_user_string <> old_lower_string
		    then

		      ! Validate that string is only numeric characters, no
		      ! spaces, special, or alpha chars. If any problems with
		      ! string, assign in a default string value.

			upper_bound = interval_string_length
			for i = 1% to upper_bound
			if pos(digits,seg$(lower_user_string,i,i),1%) = 0%
			  then
			  	i = upper_bound + 1%
			   	lower_user_string = "00"
				message = BEL + BEL + time$(0) +	&
				"*** WATCHDOG_LOWER_USERS" 		&
				+ " logcl has non-nums." + 		&
				" Deflting to 0 users."	
				sys_status = sys$brkthruw(,message, 	&
				    	operator_terminal,sendtype by value, &
					compl_status by ref,carr_ctrl by value,	&
					brkthru_flags by value,,	&
					brkthru_timeout	by value,,)

				sys_status = 0
			  end if
			next i

		  end if

		  old_lower_string = lower_user_string 		&
			if lower_user_string <> "00"

		  lower_user_limit = val%(seg$(lower_user_string,1%,	&
				interval_string_length))

		  ! If not normal return from logical translation,
		  ! then use default interval value

		  case else
			lower_user_limit = 0

			message = BEL + BEL + time$(0) +		&
			"*** WATCHDOG_LOWER_USERS"			&
			+ " logcl transl err. " +			&
			"Deflting to 0 users."

			sys_status = sys$brkthruw(,message, 	&
				operator_terminal,sendtype by value, &
				compl_status by ref,carr_ctrl by value,	&
				brkthru_flags by value,,	&
    				brkthru_timeout	by value,,)

			sys_status = 0

		end select

                return

2300

 P_2300_get_interval:

	sys_status = sys$trnlnm(,system_logical_table,		&
		interval_logical,,log_items)

		select (sys_status)

		  case (ss$_normal)

		  ! If previous string value = current string value then
		  ! no validation is necessary.

		  if interval_string <> old_interval_string
		    then

		      ! Validate that string is only
		      ! numeric characters, no spaces, special, or alpha chars
		      ! If any problems with string, assign in a default
		      ! string value for the interval.

			upper_bound = interval_string_length
			for i = 1% to upper_bound
			if pos(digits,seg$(interval_string,i,i),1%) = 0%
			  then
			  	i = upper_bound + 1%
				interval_string = default_interval
				message = BEL + BEL + time$(0) +	&
				"*** WATCHDOG_INTERVAL" 		&
				+ " logcl has non-nums." + 		&
				" Deflting to " + default_interval +	&
				" min intvl."
				sys_status = sys$brkthruw(,message, 	&
					operator_terminal,sendtype by value, &
					compl_status by ref,carr_ctrl by value,	&
					brkthru_flags by value,,	&
					brkthru_timeout	by value,,)

				sys_status = 0
			  end if
			next i

		      ! Interval value cannot be set to more than 60 minutes

			interval = val%(seg$(interval_string,1%,	&
					interval_string_length))
			if interval > one_hour
			  then interval = one_hour
			       message = BEL + BEL + time$(0) + 	&
				"*** Watchdog "				&
			       + "intvl set to max of "			&
			       + num1$(interval) + " mins."

				sys_status = sys$brkthruw(,message, 	&
					operator_terminal,sendtype by value, &
					compl_status by ref,carr_ctrl by value,	&
					brkthru_flags by value,,	&
					brkthru_timeout	by value,,)

			       sys_status = 0
			  end if

		      old_interval_string = interval_string

		      end if

		  ! If not normal return from logical translation,
		  ! then use default interval value

		  case else
			interval = val%(default_interval)

			message = BEL + BEL + time$(0) +		&
			"*** WATCHDOG_INTERVAL"				&
			+ " logcl transl err. " +			&
			"Deflting to " + default_interval + " min " +	&
			"intvl."

			sys_status = sys$brkthruw(,message, 	&
				operator_terminal,sendtype by value, &
				compl_status by ref,carr_ctrl by value,	&
				brkthru_flags by value,,	&
				brkthru_timeout	by value,,)

			sys_status = 0

		end select

                return

31000

 Error_routine:

	! Unrecoverable error - print error and message and exit

	message = BEL + BEL + time$(0) +		&
		  "*** Watchdog has crashed - BASIC Error # " + num1$(err) &
		  + "at line " + num1$(erl)

	sys_status = sys$brkthruw(,message, 	&
		operator_terminal,sendtype by value, &
		compl_status by ref,carr_ctrl by value,	&
		brkthru_flags by value,,	&
		brkthru_timeout	by value,,)

	sys_status = 0

	%page	 
32760	%sbttl "Module end"

 P_32760_Error_exit:

	message = time$(0) + "Watchdog sys_status error " +	&
		  "Process=" + process_name + ";termid=" + term

	sys_status1 = sys$brkthruw(,message, 	&
		operator_terminal,sendtype by value, &
		compl_status by ref,carr_ctrl by value,	&
		brkthru_flags by value,,	&
		brkthru_timeout	by value,,)

	sys_status1 = lib$stop(sys_status by value)

32767	end
