/* VMS-specific implementation of mlock().
 * Adapted from the anonymous "mlock_vms.c" supplied by HP with its
 * GnuPG 1.2.3 kit.
 * 2007-12-24 SMS.
 */

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>           /* Really the VMS-specific fake. */

#include <prvdef.h>
#include <ssdef.h>
#include <starlet.h>
#include <stsdef.h>

#include "config.h"
#include "util.h"


typedef struct _itemlist
{
        short buflen;
        short code;
        void *bufaddr;
        unsigned int *reslen;
} itemlist;


/* This function sets errno and vaxc$errno on error, and returns zero
 * (success) or non-zero errno (failure).
 */

int mlock( const void *addr, size_t len)
{
	int ret;
	int start_addr, end_addr;
	int lock_addr[2], retlock_addr[2];

	/* Privilege masks. */
	static union prvdef priv_mask_old = { 0 };
	static union prvdef priv_mask_new = { 0 };

	/*
	**  Attempt to set PSWAPM privilege bit for SYS$LCKPAG().
	*/
	priv_mask_new.prv$v_pswapm = 1;
	ret = sys$setprv(1,             /* Enable privileges. */
	 &priv_mask_new,                /* New privilege mask. */
	 0,                             /* Not permanent. */
	 &priv_mask_old);               /* Previous privilege mask. */

	if (ret != SS$_NORMAL)
        {
		/* SETPRV failed.  We don't have PSWAPM. */
		log_warning(
		 "PSWAPM privilege is required for secure memory on VMS.\n");
		errno = EVMSERR;
		vaxc$errno = ret;
		return errno;
        }

	/*
	**  Set address range and then lock
	*/
	lock_addr[0] = (int)addr;		/* start address */
	lock_addr[1] = (int)addr+len-1;		/* end address */

	ret = sys$lckpag(lock_addr, retlock_addr, NULL);

#ifdef DEBUG
	printf("addr=%d, len=%d\n", (int)addr, len);
	printf("inaddr1=%x %d, inaddr2=%x %d\n", lock_addr[0], lock_addr[0], lock_addr[1], lock_addr[1]);
	printf("retaddr1=%x, retaddr2=%x\n", retlock_addr[0], retlock_addr[1]);
	printf("SYS$LCKPAG() >> %d\n", ret);
#endif
	if ((ret& STS$M_SEVERITY) == STS$K_SUCCESS)
	{
		/* Success. */
		return 0;
	}
	else
	{
		/* LCKPAG failed. */
		errno = EVMSERR;
		vaxc$errno = ret;
		return errno;
	}
}


/*-----------------------------------------------------------------------*/
#ifdef TEST
int main()
{
	int *a, *a_temp, ret, i, len = 100;

	a = malloc(sizeof(int)*len);
	a_temp = a;
	for(i=0; i<len; i++){
		*a_temp = 1;
		a_temp++;
	}

	ret = mlock(a, len);

	if(ret == 0)
		printf("mlock() for OpenVMS succeeded\n");
	else
		printf("mlock_vms() for OpenVMS failed\n");

	exit(0);
}
#endif
