
;*********************************************************
;Program:	show_proc_files
;Author:	Billy Bitsenbites (Bruce Ellis)
;Synopsis:	This program displays the files currently
;		open to the specified process.  Along with 
;		each file, the number of mapping pointers
;		that map the file is displayed, as well as
;		the reads/writes on this open.
;
;
;*********************************************************

;Macro definitions
	.macro	check	?lab
	blbs	r0,lab
	$exit_s	r0
lab:
	.endm	check
;Macro library includes
	.library	/sys$library:lib/
	.link	/sys$system:sys.stb/
	$dcdef		;Device classes
	$pcbdef
	$phddef
	$pridef
	$ipldef
	$acbdef
	$ccbdef
	$wcbdef
	$fcbdef
	$ucbdef
	$secdef
	$sbdef
	$ddbdef
	$dyndef
ef=32
;data area
pid_asc:
	.long	8
	.address	10$
10$:	.blkb	8
pid:	.blkl	1
prompt:	.ascid	/Pid?/

lock_adr:
	.address	lock1
	.address	lock2

;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;Allocate header for file information buffer
;Note: Position dependence is crucial.
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
proc_files:
	.blkb	12		;reserved space for pool header info
header1=0			;;offset to the first longword (unused)
header2=4			;offset to second longword (unused)
block_size=8			;size of pool allocated to the block
block_type=10			;type of dynamic structure
prc_name:
	.blkb	16		;process name
prcnam=prc_name-proc_files	;offset to process name in block
pid_other:			;returned pid
	.long	0
pid_other_off=pid_other-proc_files	;offset to pid in block
count:	.long	0		;count of number of files open by the process
ret_count=count-proc_files	;offset to the returned count
file_buffer_loc:		;location of the file buffers
file_buffer_max=256		;philosophically we should not even allow for
				; this many concurrent files
file_buffers=file_buffer_loc-proc_files	;offset to file buffers
header=file_buffers
node=0			;offset within buffer to scs nodename
devnam=8		;offset to device name (NOTE: This program assumes
			; that precedent has not been broken with three 
			; character device names.  If it is, the area for
			; device names will have to be increased in size.
unit=12			;offset within buffer to the unit
fid=14			;offset within buffer to the file id
fid_rvn=18		;offset within the buffer to the the rvn of file
reads=20		;offset into buffer to locate the count of reads
writes=24		;offset within buffer to locate the count of writes
file_buffer_size=28	;size of each file buffer
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
; Allocate space for per file information buffers
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	.rept	file_buffer_max
	.blkb	8		;node name
	.blkb	4		;device name
	.blkb	6		;file id
	.blkl	2		;count of reads and writes
	.endr
prc_args:
	.long	2
	.address	pid
	.long	0

fmt:	.ascid	/Process: !15AC with pid !8XL has the following files open:/
out_buf:
	.long	80
	.address	10$
10$:	.blkb	80
no_file_msg:
	.ascid	/This process has no files open. /
;Code
	.psect	code	shr,nowrt,pic,exe
	.entry	show_proc_files,^m<>
	$lkwset_s	inadr=lock_adr	;No page faults at high ipl
	check
	pushal	pid_asc			;Determine which process we
	pushal	prompt			;  are supposed to get the info
	pushal	pid_asc			;  from.
	calls	#3,g^lib$get_input
	check
	pushal	pid			;Convert pid from ascii to binary
	pushal	pid_asc			;
	calls	#2,g^ots$cvt_tz_l	;
	check
	$clref_s	efn=#ef		;clear event flag we are going to wait
	check				;  on for completion of kast
	$cmkrnl_s	routin=get_file,arglst=prc_args
					;Queue a special kernel ast to the
	check				;process to obtain the needed info
	$waitfr_s	efn=#ef		;wait until sp kast sets efn for 
	check				; asynchronous completion
;**************************************************
;Format and spill the process name and PID
;**************************************************
	$fao_s	ctrstr=fmt,outbuf=out_buf,outlen=out_buf,p1=#prc_name,-
		p2=pid_other
	check
	pushal	out_buf
	calls	#1,g^lib$put_output
	movl	count,r6		;How many open files
	beql	no_files_open
	moval	proc_files+file_buffers,- ;locate the beginning of file buffers
		r7
10$:	pushl	r7			;dump the file information 1 file at
	calls	#1,spill_file_info	; a time

	addl	#<file_buffer_size>,r7	;point to next file buffer
	sobgtr	r6,10$			;loop till all files processed
over_and_out:
	ret				;Auf Wiedersehen!
no_files_open:
	pushal	no_file_msg
	calls	#1,g^lib$put_output
	brb	over_and_out

;****************************************************
;	Special kast setup
;****************************************************
lock1:
	.entry	get_file,^m<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>
;****************************************************
;	Get process PCB address
;****************************************************
;	Inputs:	4(ap)  - pidadr/ 8(ap) - prcnam desc adr / r4 - PCB
	jsb	g^exe$nampid
;	Outputs:
;		r0	-	status
;		r1	-	ipid of the other guy
;		r4	-	pcb of the other guy
;		ipl is at synch, with sched spinlock
	blbs	r0,ok2
	setipl	#0
	ret
;****************************************************
;	Allocate pool for ACB
;****************************************************
ok2:					; by exe$nampid
	movl	r4,r10			;save his pcb
	moval	acb,r6			;set up acb
	movl	g^ctl$gl_pcb,r4		;Save my 
	movl	pcb$l_pid(r4),acb_l_mypid	;  pid for return sp kast
	bbc	#pcb$v_suspen,pcb$l_sts(r10),hes_ok1
	setipl	#0
	movl	#ss$_suspended,r0
	brw	err_ret
hes_ok1:
	bbc	#pcb$v_delpen,pcb$l_sts(r10),hes_ok2
	movl	#ss$_nonexpr,r0
	brw	err_ret
hes_ok2:
	movl	@#ctl$gl_phd,r9		;get phd address
	movl	phd$l_imgcnt(r9),imgcnt	;Save the image count so return AST
					; knows whether we are in same image or
					; not
	moval	proc_files,file_ret_adr	;save return address from p0 space
	moval	count,count_ret_adr	;save return count address from p0
	movl	#size_of_pool,r1	;Set up for allocating pool
	jsb	g^exe$alononpaged	;get it
	blbs	r0,ok3			;continue if all is cool
	brw	err_ret			;else get out
ok3:	pushr	#^m<r0,r1,r2,r3,r4,r5>	;save regs from movc3
	movc3	#size_of_pool,acb,(r2)	;copy acb and routines to pool
	popr	#^m<r0,r1,r2,r3,r4,r5>	;restore regs
	movw	r1,acb$w_size(r2)	;save size of pool
	movb	#dyn$c_acb,acb$b_type(r2)	;setup type
	movb	#<1@acb$v_kast>,acb$b_rmod(r2)	;set up for sp kast
	movl	pcb$l_pid(r10),acb$l_pid(r2)	;define acb of process to get ast
	moval	<copy_file-acb>(r2),acb$l_kast(r2) ;set ast address for kast
	movl	r2,r5			;set up r5 for sch$qast
;****************************************************
;	Allocate pool for channel info
;****************************************************
	movzwl	g^sgn$gw_pchancnt,r1	;get channelcnt sysgen parameter
	cmpl	#file_buffer_max,r1	;too many channels?
	bgtr	channcnt_ok		; branch if not
	movl	#file_buffer_max,r1	;else reset to max (sorry, charlie!)
channcnt_ok:
	mull2	#file_buffer_size,r1	;calculate max buffer size needed
	addl2	#header,r1		;add on header
	movl	r1,r6			;save pool size requested
	jsb	g^exe$alononpaged		;get the pool for the buffer
	blbs	r0,still_cool		;continue if sufficient pool
	brw	err_ret_deallo		;cannot continue/not enough pool
still_cool:
	pushr	#^m<r0,r1,r2,r3,r4,r5>	;save regs for movc5
	movc5	#0,.,#0,r6,(r2)		;zero the buffer
	popr	#^m<r0,r1,r2,r3,r4,r5>	;restore regs
	movw	r1,block_size(r2)	;save the size of pool
	movb	#dyn$c_bufio,block_type(r2)
	movl	r2,file_info_buffer(r5)	;save the buffer pointer
;****************************************************
;	Queue the ast
;****************************************************
;lock1:	setipl	#ipl$_synch		;synch w/sched db
	movzwl	acb$l_pid(r5),r4	;retrieve the pid of the process we want
	movl	#pri$_ticom,r2		;give him a boost
	movl	g^ctl$gl_pcb,r4		;restore our pcb address
	jsb	g^sch$qast		;queue an ast to the process
	unlock	lockname=SCHED,newipl=#0 ;lower ipl from synch implied
	movl	#ss$_normal,r0		;Get outta here
	ret
err_ret_deallo:
	movl	file_info_buffer(r5),r0	;get pool buffer address
	beql	no_buffer_to_deallo	;
	jsb	g^exe$deanonpaged	;deallocate the buffer
no_buffer_to_deallo:
	movl	r5,r0			;r0 points to the pool to return
	jsb	g^exe$deanonpaged
	movl	#ss$_insfmem,r0
err_ret:unlock	lockname=SCHED,newipl=#0
	ret
	.psect	data_and_code	wrt,exe
acb:	.blkb	acb$l_kast+4		;allocate space for the acb portion
acb_l_mypid:
	.blkl	1		;My pid for return ast
ret_ast_adr:
	.blkl	1		;return ast address
file_info_buffer=.-acb
	.blkl	1		;location of file info buffer in pool
count_ret:
	.long	0		;return count of files processed
file_ret_adr:
	.blkl	1		;P0 buffer address
count_ret_adr:
	.blkl	1		;return location for count
imgcnt:	.blkl	1		;count of images run
;****************************************************
;	AST get file/channel info
;****************************************************

;*****************************************************
;Special kernel ast code
;*****************************************************
copy_file:
	pushr	#^m<r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>
	movl	acb_l_mypid,acb$l_pid(r5)	;reset pid for return trip
	moval	ret_ast,acb$l_kast(r5)		;set return ast address
	bisb2	#<1@acb$v_kast>,acb$b_rmod(r5)	;set up for sp kast
	movl	file_info_buffer(r5),r11	;locate the buffer
	movl	g^ctl$gl_pcb,r10		;get this guy's pcb address
	movq	pcb$t_lname(r10),prcnam(r11)	;copy the process name
	movq	<pcb$t_lname+8>(r10),<prcnam+8>(r11)	;copy the rest
	movl	pcb$l_epid(r10),pid_other_off(r11)	;get his pid
	moval	file_buffers(r11),r9		;locate the file buffers
	clrl	ret_count(r11)			;zero counter of file names
	movl	@#ctl$gl_ccbbase,r10		;set up link to fix up vectors
	clrl	r6
	movl	g^ctl$gl_pcb,r4
	moval	g^ioc$gl_mutex,r0
	jsb	g^sch$lockr
nxt_ccb:					;Index from base back
	subl	#16,r10				; 1 CCB at a time 
	addl	#16,r6				;keep track of current chan #
	cmpw	r6,g^ctl$gw_chindx		;if past max scram
	bgtr	done
	movl	ccb$l_ucb(r10),r7		;get ucb
	beql	all_done1
	cmpb	#dc$_disk,ucb$b_devclass(r7)	;if not a disk skip it
	bneq	not_a_file
	movl	ccb$l_wind(r10),r8		;get wcb
	beql	not_a_file
	blss	not_a_section_file
	cvtwl	ccb$l_wind(r10),r2		;get negative pstx out of ccb
	movl	g^ctl$gl_phd,r1			;get the phd address
	addl2	phd$l_pstbasoff(r1),r1		;locate the end of the pst
	movl	sec$l_window(r1)[r2],r8		;get the wcb pointer
not_a_section_file:
	movl	wcb$l_reads(r8),reads(r9)	;get reads since open
	movl	wcb$l_writes(r8),writes(r9)	;get writes since open
	movl	wcb$l_fcb(r8),r8		;get fcb
	movl	fcb$w_fid(r8),fid(r9)		;get file id
	movw	fcb$w_fid_rvn(r8),fid_rvn(r9)	;get rest of fid
	movw	ucb$w_unit(r7),unit(r9)		;get unit number
	movl	ucb$l_ddb(r7),r7		;get the device name
	movl	ddb$t_name(r7),devnam(r9)
	movl	ddb$l_allocls(r7),<node+2>(r9)	;get allo class if any
	beql	no_alloclass			; branch if none
	movw	#-1,node(r9)			;mark that alloclass exists
	brb	skip_name			;don't need name
no_alloclass:
	movl	ddb$l_sb(r7),r7			;get the node name
	movl	sb$t_nodename(r7),node(r9)	;
	movl	sb$t_nodename+4(r7),<node+4>(r9)
skip_name:
	incl	ret_count(r11)			;count fo files +=1
	cmpw	#file_buffer_max,ret_count(r11)	;too many?
	blss	all_done1
	addl2	#file_buffer_size,r9		;point to next buffer
not_a_file:
all_done2:
	brw	nxt_ccb				;get the next file
done:
all_done1:
;****************************************************
;	AST return file/channel info
;****************************************************
;*****************************************************
;We have the info now let us send it back to the 
;original process.
;*****************************************************
	movl	g^ctl$gl_pcb,r4
	moval	g^ioc$gl_mutex,r0
	jsb	g^sch$unlock
	lock	lockname=SCHED,lockipl=#ipl$_sched
	movzwl	acb$l_pid(r5),r1		;set up return pid for astdel
	movl	g^sch$gl_pcbvec,r2		;get at pcb vector table
	movl	(r2)[r1],r1			;get our pcb address
						;Who are we anyway? (Zelig)
	cmpl	pcb$l_pid(r1),acb$l_pid(r5)	;are we still around or are we
						; The Ghost in the Machine
	bneq	err_ast_exit			;if initial process is not
						;here exit
	unlock	lockname=SCHED,newipl=#ipl$_astdel
	clrl	r2				;no boost for the ast
	jsb	g^sch$qast			;return to home
	setipl	#ipl$_astdel			;return to initial ipl
	popr	#^m<r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>
	rsb					;back to astdel
err_ast_exit:
	unlock	lockname=SCHED,newipl=#ipl$_astdel
	popr	#^m<r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>
	movl	file_info_buffer(r5),r0		;return file info buffer to 
						;pool
	jsb	g^exe$deanonpaged		;
	movl	r5,r0				;deallocate ourselves
	jmp	g^exe$deanonpaged		;and don't come back here 
						;instead go directly back to
						;astdel and do not collect $200
;****************************************************************
;We are back home now so lets put the info at his
;doorstep, ring the doorbell, and disappear
;****************************************************************
ret_ast:
	pushr	#^m<r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>
	movl	pcb$l_phd(r4),r3		;get our process header
	cmpl	phd$l_imgcnt(r3),imgcnt		;are we still in the same
						;image? If not get out.
	bneq	exit				;
	movl	file_info_buffer(r5),r6		;locate the file info buffer

	mull3	#<file_buffer_size>,-		;
		ret_count(r6),r2		;how much to return?
	addl2	#header,r2			;return header info
	pushr	#^m<r0,r1,r2,r3,r4,r5>
	movc3	r2,(r6),-			;
		@file_ret_adr			;return the goods
	popr	#^m<r0,r1,r2,r3,r4,r5>
	movl	ret_count(r6),@count_ret_adr	;return the count
	movl	#ef,r3				;set efn ef
	movl	pcb$l_pid(r4),r1		;for ourselves
	clrl	r2				;no boost
	jsb	g^sch$postef			; set it
exit:	popr	#^m<r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>
	movl	file_info_buffer(r5),r0		;return file info buffer to 
						;pool
	jsb	g^exe$deanonpaged		;
	movl	r5,r0
	jmp	g^exe$deanonpaged		;become a nonentity
size_of_pool = .-acb
lock2:
	.end	show_proc_files	






;******************************************************
;	Subroutine - Spill_File_Info
;	Author:	Billy Bitsenbites (Bruce Ellis)
;	Synopsis:	This subroutine is called to
;		format and display the Device name, file
;		name, file id, reads and writes on the
;		file since opened, and the number of mapping
;		pointers in the file header(s).
;	Inputs:	address of a block of the following form:
;		8 bytes containing the scsnode
;		4 bytes containing the device name
;		2 bytes containing the unit number of the device
;		6 bytes containing the file id of the file
;		4 bytes containing the count of reads on the window
;		4 bytes containing the count of writes on the window
;
;******************************************************


;Macros
	.macro	check	?l
	blbs	r0,l
	$exit_s	r0
l:
	.endm	check
;Data
dev:	.long	15		;Descriptor holding the device name
	.address	dev_a
dev_a:	.blkb	15
out_string:			;Output string buffer
	.long	256
	.address	10$
10$:	.blkb	256

;formats
file_dev:
	.ascid	<10><13>/File:/
fid_fmt:.ascid	/File id: (!UW,!UW,!UW)/
fmt_rw:	.ascid	/Reads on window: !10UL         Writes on window: !10UL/
out_ptr:			;Output buffer
	.long	80
	.address	10$
10$:	.blkb	80
ptr_count:			;Count of the number of mapping pointers
	.blkl	1
file_buffer:			;Local copy of the passed file buffer
node:	.blkb	8
devnam:	.blkb	4
unit:	.blkw	1
fid:	.blkb	6
reads:	.long	0
writes:	.long	0
buffer_size=.-file_buffer
allo:	.long	3		;Allocation class descriptor
	.address	allo_a
allo_a_prefix:
	.ascii	/$/
allo_a:	.blkb	3
allo_f:	.ascid	/!UB/
unit_f:	.ascid	/!UW/
unit_d:	.long	5
	.address	unit_a
unit_a:	.blkb	5

;Code

	.entry	spill_file_info,^m<>
	movc3	#buffer_size,@4(ap),file_buffer	;Copy the buffer to local
						; storage
	cmpw	node,#-1			;Alloclass?
	bneq	no_alloclass			;branch if not
;^^^^^^^^^^^^
;Format the allocation class to ascii
;^^^^^^^^^^^^
	$fao_s	ctrstr=allo_f,outbuf=allo,outlen=allo,p1=node+2
	check
	incl	allo				;increment to include
						; last '$' sign
	movc3	allo,allo_a_prefix,dev_a
	brb	finish_node			;skip to rest of devnam
no_alloclass:
	movzbl	node,r0				;Get node name size
	bneq 	got_node			;Process the node name
	moval	dev_a,r3			;no node so skip it
	brb	skip_node			;
got_node:
	movc3	r0,<node+1>,dev_a		;Copy node name
finish_node:
	movb	#^a/$/,(r3)+		;Plug in a $ after node name
skip_node:
	movw	devnam+1,(r3)+		; Get device and controller
	movb	devnam+3,(r3)+		; portion of the device name
	movl	#5,unit_d		;Format the unit #
	$fao_s	ctrstr=unit_f,outbuf=unit_d,outlen=unit_d,p1=unit
	check
	movc3	unit_d,unit_a,(r3)	;Append unit (in ascii) to devnam
	movb	#^a/:/,(r3)+		;Append ':'
	subl3	#dev_a,r3,dev		;Calculate size of device name
	pushal	file_dev		;Spill header
	calls	#1,g^lib$put_output	
	movl	#256,out_string		;Alllow for a large file name
	pushal	out_string		;Pass location to return size
					; of file name string
	pushal	out_string		;Pass file spec descriptor
	pushal	fid			;Pass the file id
	pushal	dev			;Pass the device name
	calls	#4,g^lib$fid_to_name	;Convert the fid to file name
	check
	pushal	out_string		;spill the file name
	calls	#1,g^lib$put_output
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;Format the file id
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	movl	#80,out_ptr
	$fao_s	ctrstr=fid_fmt,outbuf=out_ptr,outlen=out_ptr,-
		p1=fid,p2=fid+2,p3=fid+4
	check
	pushal	out_ptr
	calls	#1,g^lib$put_output	;Spill the file id
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;format the count of reads/writes
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	movl	#80,out_ptr
	$fao_s	ctrstr=fmt_rw,outbuf=out_ptr,outlen=out_ptr,p1=reads,-
		p2=writes
	check
	pushal	out_ptr			;Spill the count
	calls	#1,g^lib$put_output
	ret				;Sayonara
	.end

