    .title jcf_freeblocks - Get free blocks
    .ident /01/

;++
; 
; This module contains the routines required to return the number
; of free blocks on a disk volume as a percentage of total storage
; capacity.
;
; Neal Lippman, August, 1980
;
;--

.library 'sys$library:lib'
$dcdef
$ssdef
$ucbdef
$vcbdef


;
; this routine returns the percentage of free blocks on the input
; volume.
;
; Inputs:
;	4(ap) -> address of device name descriptor
;	8(ap) -> address to put percent blocks free
;
; return status codes:
;	ss$_accvio if cannot read buffers
;	ss$_nopriv if cannot cmkrnl
;	ss$_ivdevnam if not a disk device
;	ss$_devnotmount if device is not mounted
;	ss$_nosuchdev if device does not exist
;	return code for lckpag system service if failure 
;
; Requires CMKRNL, PSWAPM, maybe other privileges
;


	.psect data,rd,wrt

status_code:
	.blkw	1
lckpages:
	.long	k_start,k_end


	.psect $$$exe$$$,rd,nowrt

jcf_getfreeblocks::
	.word	^m<r2,r3,r4,r5>

	movl	4(ap),r2		;get address of device name descr
	movl	8(ap),r3		;get address of freeblocks buffer
	ifnowrt	#4,(r3),10$,#3		;br if we cannot write return buffer
	ifnord	#8,(r2),10$		;br if we cannot read dev descr
	$lckpag_s	inadr=lckpages	;lock kernel routine in memory
	blbc	r0,20$			;br if error
	$cmkrnl_s 	routin=get_data	;get the info...return free blocks
					;into r4 and total blocks into r5
	blbc	r0,20$			;br if error in cmkrnl
 	blbc	status_code,30$		;br if error in cmrnl routine
	cvtlf	r10,r10			;convert free blocks to floating
	cvtlf	r5,r5			;convert total blocks to floating
	mulf2	#^f100,r10		;multiply by 100 first
	divf2	r5,r10			;divide them to get percent used
	movf	r10,@8(ap)		;put number in return buffer
5$:	movzwl	#ss$_normal,r0		;set success
	ret				;and return	
10$:	movzwl	#ss$_accvio,r0		;set access violation
20$:	ret				;and return
30$:	movzwl	status_code,r0
	ret

;
; This routine executes in kernel mode to get the number of free blocks
; from the volume control block of the device
;


k_start:
get_data:
	.word	^m<r6,r7,r8>		;save nothing...
	movl	sch$gl_curpcb,r4	;set addr of current pcb
	movl	r2,r7			;save addr of device descr
	jsb	g^sch$iolockr		;lock I/O  database for read
	movl	r7,r1			;set addr of device descr
	jsb	g^ioc$searchdev		;look for the device
	blbs	r0,10$			;br if found
	movzwl	#ss$_nosuchdev,status_code ;set dev not found code
	brw	20$			;and go away

10$:
	movl	r1,r6			;save ucb address
	movl	ucb$l_vcb(r6),r7	;get addr of volume control block
	cmpb	#dc$_disk,ucb$b_devclass(r6) ;is this a disk volume?
	bneq	30$			;br if not
	bbc	#ucb$v_valid,ucb$w_sts(r6),40$ ;br if not software valid


	movl	vcb$l_free(r7),r10	;get number of free blocks
	movl	ucb$l_maxblock(r6),r5	;get number of blocks
	movl	#1,status_code		;success in r1 (r1 is status reg for
					;kernel routine)

20$:	movl	#1,r0			;set success
	jmp	g^ioc$unlock		;unlock I/O data base and return
;	ret				;and return

30$:	movzwl	#ss$_ivdevnam,status_code ;set invalid device
	brb	20$			;and go away

40$:	movzwl	#ss$_devnotmount,status_code ;set device offline
	brb	20$			;and go away
k_end:
	.end
