/*
 * |-----------------------------------------------------------|
 * | Copyright (c) 1991, 1990 MIPS Computer Systems, Inc.      |
 * | All Rights Reserved                                       |
 * |-----------------------------------------------------------|
 * |          Restricted Rights Legend                         |
 * | Use, duplication, or disclosure by the Government is      |
 * | subject to restrictions as set forth in                   |
 * | subparagraph (c)(1)(ii) of the Rights in Technical        |
 * | Data and Computer Software Clause of DFARS 252.227-7013.  |
 * |         MIPS Computer Systems, Inc.                       |
 * |         950 DeGuigne Avenue                               |
 * |         Sunnyvale, California 94088-3650, USA             |
 * |-----------------------------------------------------------|
 */
#ident	"$Header: prot_pnlm.c,v 1.7.2.1 92/06/24 13:50:47 marker Exp $"

#include <bsd43/sys/types.h>
#include <stdio.h>
#include <sys/fcntl.h>
#include <netinet/in.h>
#include "prot_lock.h"

#define DEBUG_ON        57
#define DEBUG_OFF       58
#define KILL_IT         59

int			nlm;
extern FILE 		*fp;
SVCXPRT 		*nlm_transp;	/* export nlm transport handle */

extern int 		grace_period, LockID;
extern int 		lock_len, res_len;
extern msg_entry        *msg_q; 
extern msg_entry 	*queue();
extern remote_result 	*get_res();
extern reclock 		*get_reclock();
 
#ifdef RISCOS
#define call_rpc(name,pnum,ver,func,xdr_arg,args,xdr_proc,num1,valid,num2) \
 call_udp(name,pnum,ver,func,xdr_arg,args,xdr_proc,num1,valid,num2)
#endif

#ifdef RISCOS_DEBUG
extern char *xmalloc_debug();
#else
extern char *xmalloc();
#endif

extern msg_entry    *klm_msg;
extern remote_result 	res_nolock;
extern remote_result 	res_working;
extern remote_result 	res_grace;

extern int 		debug;

extern msg_entry 	*search_msg();
extern remote_result 	*local_lock();
extern remote_result 	*local_unlock();
extern remote_result 	*local_test();
extern remote_result 	*local_cancel();
extern remote_result 	*cont_test();
extern remote_result 	*cont_lock();
extern remote_result 	*cont_unlock();
extern remote_result 	*cont_cancel();
extern remote_result 	*cont_reclaim();

extern nlm_testargs 	*get_nlm_testargs();
extern nlm_lockargs 	*get_nlm_lockargs();
extern nlm_unlockargs 	*get_nlm_unlockargs();
extern nlm_cancargs 	*get_nlm_cancargs();
extern nlm_testres	*get_nlm_testres();

int
proc_nlm_test(a)
	struct reclock *a;
{
	remote_result *result;

	if (debug)
		printf("proc_nlm_test(%x) \n", a);
	result = local_test(a);
	nlm_reply(NLM_TEST, result, a);
}

int
proc_nlm_lock(a)
	struct reclock *a;
{
	remote_result *result;


	if (debug)
		printf("enter proc_nlm_lock(%x) \n", a);
	result = local_lock(a);
	nlm_reply(NLM_LOCK, result, a);
}

int
proc_nlm_cancel(a)
	struct reclock *a;
{
	remote_result *result;

	if (debug)
		printf("enter proc_nlm_cancel(%x) \n", a);
	result = local_cancel(a);
	nlm_reply(NLM_CANCEL, result, a);
}

int
proc_nlm_unlock(a)
	struct reclock *a;
{
	remote_result *result;

	if (debug)
		printf("enter proc_nlm_unlock(%x) \n", a);
	result = local_unlock(a);
	nlm_reply(NLM_UNLOCK, result, a);
}

int
proc_nlm_test_msg(a)
	struct reclock *a;
{
	remote_result *result;

	if (debug)
		printf("enter proc_nlm_test_msg(%x)\n", a);
	result = local_test(a);
	nlm_reply(NLM_TEST_MSG, result, a);
}

int
proc_nlm_lock_msg(a)
	struct reclock *a;
{
	remote_result *result;

	if (debug)
		printf("enter proc_nlm_lock_msg(%x)\n", a);
	result = local_lock(a);
	nlm_reply(NLM_LOCK_MSG, result, a);
}

int
proc_nlm_cancel_msg(a)
	struct reclock *a;
{
	remote_result *result;

	if (debug)
		printf("enter proc_nlm_cancel_msg(%x)\n", a);
	result = local_cancel(a);
	nlm_reply(NLM_CANCEL_MSG, result, a);
}

int
proc_nlm_unlock_msg(a)
	struct reclock *a;
{
	remote_result *result;

	if (debug)
		printf("enter proc_nlm_unlock_msg(%x)\n", a);
	result = local_unlock(a);
	nlm_reply(NLM_UNLOCK_MSG, result, a);
}

/*
 * return rpc calls;
 * if rpc calls, directly reply to the request;
 * if msg passing calls, initiates one way rpc call to reply!
 */
int
nlm_reply(proc, reply, a)
	int proc;
	remote_result *reply;
	struct reclock *a;
{
	bool_t (*xdr_reply)();
	int act, rpc_err, valid;
	int nlmreply = 1;
	int newcall = 2;
	char *name;

	switch (proc) {
	case NLM_TEST:
		xdr_reply = xdr_nlm_testres;
		act = nlmreply;
		break;
	case NLM_LOCK:
	case NLM_CANCEL:
	case NLM_UNLOCK:
		xdr_reply = xdr_nlm_res;
		act = nlmreply;
		break;

	case NLM_TEST_MSG:
		xdr_reply = xdr_nlm_testres;
		act = newcall;
		proc = NLM_TEST_RES;
		name = a->lck.clnt_name;
		if (a->lck.lox.lld.l_type == F_UNLCK) {
			reply->lstat = nlm_granted;
		} else {
			reply->lstat = nlm_denied;
			reply->stat.nlm_testrply_u.holder.svid =
				a->lck.lox.lld.l_pid;
			reply->stat.nlm_testrply_u.holder.l_offset =
				a->lck.lox.lld.l_start;
			reply->stat.nlm_testrply_u.holder.l_len =
				a->lck.lox.lld.l_len;
			reply->stat.nlm_testrply_u.holder.exclusive =
			 (a->lck.lox.lld.l_type == F_WRLCK) ? TRUE : FALSE;
		}
		if (debug) {
		  printf("NLM_REPLY : stat=%d svid=%d l_offset=%d l_len=%d\n",
			 reply->lstat,
			 reply->stat.nlm_testrply_u.holder.svid,
			 reply->stat.nlm_testrply_u.holder.l_offset,
			 reply->stat.nlm_testrply_u.holder.l_len);
		}
		break;

	case NLM_LOCK_MSG:
		xdr_reply = xdr_nlm_res;
		act = newcall;
		proc = NLM_LOCK_RES;
		name = a->lck.clnt_name;
		break;
	case NLM_CANCEL_MSG:
		xdr_reply = xdr_nlm_res;
		act = newcall;
		proc = NLM_CANCEL_RES;
		name = a->lck.clnt_name;
		break;
	case NLM_UNLOCK_MSG:
		xdr_reply = xdr_nlm_res;
		act = newcall;
		proc = NLM_UNLOCK_RES;
		name = a->lck.clnt_name;
		break;
	default:
		printf("unknown nlm_reply proc value: %d\n", proc);
		return;
	}
	if (act == nlmreply) { /* reply to nlm_transp */
		if (debug)
			printf("rpc nlm_reply %d: %d\n", proc, reply->lstat);
		if (!svc_sendreply(nlm_transp, xdr_reply, &reply))
			svcerr_systemerr(nlm_transp);
		return;
	}
	else { /* issue a one way rpc call to reply */
		if (debug)
			printf("nlm_reply: (%s, %d), result = %d\n",
			name, proc, reply->lstat);
		reply->cookie_len = a->cookie_len;
		reply->cookie_bytes = a->cookie_bytes;
		valid = 1;
#ifdef NOTUSE
		if ((rpc_err = call_rpc(name, NLM_PROG, NLM_VERS, proc,
			xdr_reply, reply, xdr_void, NULL, valid, 0))
			!= (int) RPC_TIMEDOUT && rpc_err != (int) RPC_SUCCESS) {
			/* in case of error, print out error msg */
			clnt_perrno(rpc_err);
			fprintf(stderr, "\n");
		} else if (rpc_err == RPC_TIMEDOUT) { /* Bug Fix : 1014808 */
			if ((rpc_err = call_rpc(name, NLM_PROG, NLM_VERS, proc,
				xdr_reply, reply, xdr_void, NULL, 0, 0))
				!= (int) RPC_TIMEDOUT &&
				rpc_err != (int) RPC_SUCCESS) {
				/* in case of error, print out error msg */
				clnt_perrno(rpc_err);
				fprintf(stderr, "\n");
			}
		}
#endif
		if ((rpc_err = call_rpc(name, NLM_PROG, NLM_VERS, proc,
                        xdr_reply, reply, xdr_void, NULL, valid, 0))
                        != (int) RPC_TIMEDOUT && rpc_err != (int) RPC_CANTSEND)
		        { /* in case of error, print out error msg */
                        clnt_perrno(rpc_err);
                        fprintf(stderr, "\n");
                } else if (rpc_err == RPC_CANTSEND) {
                        if ((rpc_err = call_rpc(name, NLM_PROG, NLM_VERS, proc,
                                xdr_reply, reply, xdr_void, NULL, 0, 0))
                                != (int) RPC_TIMEDOUT &&
			     rpc_err != (int) RPC_CANTSEND) {
                                /* in case of error, print out error msg */
                                clnt_perrno(rpc_err);
                                fprintf(stderr, "\n");
                        }
                }
	}
}

int
proc_nlm_test_res(reply)
	remote_result *reply;
{
	nlm_res_routine(reply, cont_test);
}

int
proc_nlm_lock_res(reply)
	remote_result *reply;
{
	nlm_res_routine(reply, cont_lock);
}

int
proc_nlm_cancel_res(reply)
	remote_result *reply;
{
	nlm_res_routine(reply, cont_cancel);
}

int
proc_nlm_unlock_res(reply)
	remote_result *reply;
{
	nlm_res_routine(reply, cont_unlock);
}

/*
 * common routine shared by all nlm routines that expects replies from server
 * network lock mgr: nlm_lock_res, nlm_test_res, nlm_unlock_res, nlm_cancel_res
 * private routine "cont" is called to continue local operation;
 * reply is match with msg in msg_queue according to cookie
 * and then attached to msg_queue;
 */
int
nlm_res_routine(reply, cont)
	remote_result *reply;
	remote_result *(*cont)();
{
	msg_entry *msgp;
	remote_result *resp;

	if (debug) {
		printf("enter nlm_res_routine...\n");
		pr_all();
		(void) fflush(stdout);
	}
	if ((msgp = search_msg(reply)) != NULL) { /* found */

		if (msgp->reply != NULL) { /* existing reply already exists */

			if (msgp->reply->lstat != reply->lstat) {
			  fprintf(stderr,
"inconsistent lock reply; lock= %x; reply status' old= %d; new= %d; ignored\n",
				msgp->req, msgp->reply->lstat, reply->lstat);

			}
			release_res(reply);
#ifdef RISCOS
                        /* 
			 * When duplicate or inconsistent reply msg received
			 * drop the queue entry if reply's return status
			 * indicate blocking lock request on the server end!
			 */
                        if (msgp->reply->lstat == blocking) {
				msgp->req->rel = 1;
				dequeue(msgp);
			}
#else
                        if (msgp->reply->lstat == blocking)
				dequeue(msgp);
#endif
			return;
		}

		/*
		 * Continue processing request according to the reply's
		 * return status. Update the file lock table and msg queue
		 * entry accordingly.
		 */
		if (msgp->proc == NLM_LOCK_RECLAIM) { /* reclaim response */
		  resp = cont_reclaim(msgp->req, reply);
		}
		else { /* normal response */
		  resp = cont(msgp->req, reply);
		}

		/* Send the proper reply depending on 'cont' proc's return */
		add_reply(msgp, resp);
#ifdef RISCOS
		/*
		 * add_reply dequeue's the msg entry if it was the last
		 * message on the queue to send to klm. This was added by
		 * the original author as a performance optimization so that
		 * the message would be processed immediately; BUT they
		 * forgot to check AFTER the return whether the msg entry
		 * was removed from the queue and was deallocated. The result
		 * was a lock manager daemon crash with a bogus address.
		 *
		 * IF reply was sent (klm_msg is null) AND the response
		 * indication from the continue procedure is not null and
		 * the response status was blocking them the entry was
		 * NOT removed so we need to check if we should remove the
		 * msg queue entry.
		 */
                if ((klm_msg != NULL) && (resp != NULL)) {
		    if (resp->lstat == blocking) { /* msg entry NOT removed */
			  if (msgp->reply->lstat == blocking) {
			    msgp->req->rel = 1;
			    dequeue(msgp);
			  }
		    }
		 }
#else
                if (msgp->reply->lstat == blocking)
                        dequeue(msgp);
#endif
	}
	else
		release_res(reply);	/* discard this reply */
}

/*
 * rpc msg passing calls to nlm msg procedure
 * This procedure is used by local_lock, local_test, local_cancel, local_unloc
 *
 * The parameters to this procedure are:
 * proc specifies the name of nlm procedure
 * a holds the record lock specifies for this request
 * retransmit indicates whether this is retransmission
 * 
 * rpc_call return -1 if rpc call is not successful then
 * clnt_perrno is printed out; othersize rpc_call returns 0.
 */
int
nlm_call(proc, a, retransmit)
	int proc;
	struct reclock *a;
	int retransmit;
{
	int 		retval,	rpc_err;
	bool_t 		(*xdr_arg)();
	char 		*name, *args;
	int 		func, valid;
	nlm_testargs 	*nlm_testargs_a;
	nlm_lockargs 	*nlm_lockargs_a;
	nlm_cancargs 	*nlm_cancargs_a;
	nlm_unlockargs 	*nlm_unlockargs_a;

	func = proc;		/* this is necc for NLM_LOCK_RECLAIM */

	if (retransmit == 0)
		valid = 1;	/* use cache value for first time calls */
	else
		valid = 0;	/* invalidate cache */

	switch (proc) {

	case NLM_TEST_MSG:
		xdr_arg = xdr_nlm_testargs;
		name = a->lck.svr;
		if ((nlm_testargs_a = get_nlm_testargs()) == NULL) {
			printf("rpc.lockd: nlm_call unable to allocate nlm_testargs.\n");
			return (-1);
		}

		retval = reclocktonlm_testargs(a, nlm_testargs_a);
		if (retval == -1) {
#ifdef RISCOS_DEBUG
		  xfree_debug(&nlm_testargs_a, __FILE__, __LINE__);
#else
		  xfree(&nlm_testargs_a);
#endif
		  printf("rpc.lockd: nlm_call unable to translate nlm_testargs.\n");
		  return retval;
		}

		args = (char *)nlm_testargs_a;
		break;

	case NLM_LOCK_RECLAIM:
		func = NLM_LOCK_MSG;
		valid = 0;	/* turn off udp cache */

	case NLM_LOCK_MSG:
		xdr_arg = xdr_nlm_lockargs;
		name = a->lck.svr;
		if ((nlm_lockargs_a = get_nlm_lockargs()) == NULL) {
		  printf("rpc.lockd: nlm_call unable to allocate nlm_lockargs.\n");
		  return (-1);
		}

		retval = reclocktonlm_lockargs(a, nlm_lockargs_a);
		if (retval == -1) {
#ifdef RISCOS_DEBUG
		  xfree_debug(&nlm_lockargs_a, __FILE__, __LINE__);
#else
		  xfree(&nlm_lockargs_a);
#endif
		  printf("rpc.lockd: nlm_call unable to translate nlm_lockargs.\n");
		  return retval;
		}

		args = (char *)nlm_lockargs_a;
		break;

	case NLM_CANCEL_MSG:
		xdr_arg = xdr_nlm_cancargs;
		name = a->lck.svr;
		if ((nlm_cancargs_a = get_nlm_cancargs()) == NULL) {
			printf("rpc.lockd: nlm_call unable to allocate nlm_cancargs.\n");
			return (-1);
		}

		retval = reclocktonlm_cancargs(a, nlm_cancargs_a);
		if (retval == -1) {
#ifdef RISCOS_DEBUG
		  xfree_debug(&nlm_cancargs_a, __FILE__, __LINE__);
#else
		  xfree(&nlm_cancargs_a);
#endif
		  printf("rpc.lockd: nlm_call unable to translate nlm_cancargs.\n");
		  return retval;
		}

		args = (char *)nlm_cancargs_a;
		break;

	case NLM_UNLOCK_MSG:
		xdr_arg = xdr_nlm_unlockargs;
		name = a->lck.svr;
		if ((nlm_unlockargs_a = get_nlm_unlockargs()) == NULL) {
		  printf("rpc.lockd: nlm_call unable to allocate nlm_unlockargs.\n");
		  return (-1);
		}

		retval = reclocktonlm_unlockargs(a, nlm_unlockargs_a);
		if (retval == -1) {
#ifdef RISCOS_DEBUG
		  xfree_debug(&nlm_unlockargs_a, __FILE__, __LINE__);
#else
		  xfree(&nlm_unlockargs_a);
#endif
		  printf("rpc.lockd: nlm_call unable to translate nlm_unlockargs.\n");
		  return retval;
		}
		args = (char *)nlm_unlockargs_a;
		break;

	default:
		printf("%d not supported in nlm_call\n", proc);
		return (-1);
	}

	if (debug)
		printf("nlm_call (%s,%d); op=%d(%d,%d);retran= %d;valid= %d\n",
			name, proc, a->lck.op, a->lck.lox.lld.l_start,
			a->lck.lox.lld.l_len, retransmit, valid);

	retval = 0;
	if (proc == NLM_LOCK_MSG || proc == NLM_UNLOCK_MSG ||
		proc == NLM_TEST_MSG || proc == NLM_CANCEL_MSG ||
		proc == NLM_LOCK_RECLAIM ) {
		/*
		 * call is a one way rpc call to simulate msg passing
		 * no timeout nor reply is specified;
		 */
		if ((rpc_err = call_rpc(name, NLM_PROG, NLM_VERS, func,
			xdr_arg, args, xdr_void, NULL, valid, 0)) ==
			(int)RPC_TIMEDOUT ) {
			/*
			 * if rpc call is successful, add msg to msg_queue
			 */
			if (retransmit == 0)	/* first time calls */
				if (queue(a, proc) == NULL) { /* failed */
					retval = -1;
				}
		} else {
			if (debug) {
				clnt_perrno(rpc_err);
				fprintf(stderr, "\n");
			}
			retval = -1;
		}

		/*
		 * Release the nlm specific arguments prior to exiting
		 */
		switch (proc) {

		case NLM_TEST_MSG:
			release_nlm_testargs(nlm_testargs_a);
			break;

		case NLM_LOCK_MSG:
			release_nlm_lockargs(nlm_lockargs_a);
			break;

		case NLM_CANCEL_MSG:
			release_nlm_cancargs(nlm_cancargs_a);
			break;

		case NLM_UNLOCK_MSG:
			release_nlm_unlockargs(nlm_unlockargs_a);
			break;

		default:
			break;
		}
	}
	return retval;
}

int
reclocktonlm_lockargs(from, to)
	struct reclock *from;
	nlm_lockargs   *to;
{
	int retval;

	if (from->cookie.n_len) {
		retval = obj_copy(&to->cookie, &from->cookie);
		if (retval == -1) return retval;
	}
	to->block = (from->block) ? TRUE : FALSE;
	to->exclusive = (from->lck.lox.lld.l_type == F_WRLCK) ? TRUE : FALSE;

#ifdef RISCOS_DEBUG
	to->alock.caller_name = xmalloc_debug (
		strlen(from->alock.caller_name)+1, __FILE__, __LINE__);
#else
	to->alock.caller_name = xmalloc(strlen(from->alock.caller_name)+1);
#endif
	if (to->alock.caller_name == NULL) {
		if (from->cookie.n_len) obj_free(&to->cookie);
		return (-1);
	}
	strcpy (to->alock.caller_name, from->alock.caller_name);

	if (from->alock.fh.n_len) {
		retval = obj_copy(&to->alock.fh, &from->alock.fh);
		if (retval == -1) {
#ifdef RISCOS_DEBUG
			xfree_debug(&to->alock.caller_name,
				    __FILE__, __LINE__);
#else
			xfree(&to->alock.caller_name);
#endif
			if (from->cookie.n_len) obj_free(&to->cookie);
			return retval;
		}
	}
	else {
		to->alock.fh.n_len = 0;
		to->alock.fh.n_bytes = 0;
	}

	if (from->alock.oh.n_len) {
		retval = obj_copy(&to->alock.oh, &from->alock.oh);
		if (retval == -1) {
			if (from->alock.fh.n_len) obj_free(&to->alock.fh);
#ifdef RISCOS_DEBUG
			xfree_debug(&to->alock.caller_name,
				    __FILE__, __LINE__);
#else
			xfree(&to->alock.caller_name);
#endif
			if (from->cookie.n_len) obj_free(&to->cookie);
			return retval;
		}
	}
	else {
		to->alock.oh.n_len = 0;
		to->alock.oh.n_bytes = 0;
	}

	to->alock.svid = from->alock.lox.lld.l_pid;
	to->alock.l_offset = from->alock.lox.lld.l_start;
	to->alock.l_len = (from->alock.lox.lld.l_len == 0)
	  ? 0x7fffffff : from->alock.lox.lld.l_len;
	to->reclaim = from->reclaim;
	to->state = from->state;
	return 0;
}

int
reclocktonlm_cancargs(from, to)
	struct reclock *from;
	nlm_cancargs   *to;
{
	int retval;

	if (from->cookie.n_len) {
		retval = obj_copy(&to->cookie, &from->cookie);
		if (retval == -1) return retval;
	}
	to->block = (from->block) ? TRUE : FALSE;
	to->exclusive = (from->lck.lox.lld.l_type == F_WRLCK) ? TRUE : FALSE;

#ifdef RISCOS_DEBUG
	to->alock.caller_name = xmalloc_debug (
		strlen(from->alock.caller_name)+1, __FILE__, __LINE__);
#else
	to->alock.caller_name = xmalloc(strlen(from->alock.caller_name)+1);
#endif
	if (to->alock.caller_name == NULL) {
		if (from->cookie.n_len) obj_free(&to->cookie);
		return (-1);
	}

	if (from->alock.fh.n_len) {
		retval = obj_copy(&to->alock.fh, &from->alock.fh);
		if (retval == -1) {
#ifdef RISCOS_DEBUG
			xfree_debug(&to->alock.caller_name,
				    __FILE__, __LINE__);
#else
			xfree(&to->alock.caller_name);
#endif
			if (from->cookie.n_len) obj_free(&to->cookie);
			return retval;
		}
	}
	else {
		to->alock.fh.n_len = 0;
		to->alock.fh.n_bytes = 0;
	}
	if (from->alock.oh.n_len) {
		retval = obj_copy(&to->alock.oh, &from->alock.oh);
		if (retval == -1) {
			if (from->alock.fh.n_len) obj_free(&to->alock.fh);
#ifdef RISCOS_DEBUG
			xfree_debug(&to->alock.caller_name,
				    __FILE__, __LINE__);
#else
			xfree(&to->alock.caller_name);
#endif
			if (from->cookie.n_len) obj_free(&to->cookie);
			return retval;
		      }
	}
	else {
		to->alock.oh.n_len = 0;
		to->alock.oh.n_bytes = 0;
	      }
	to->alock.svid = from->alock.lox.lld.l_pid;
	to->alock.l_offset = from->alock.lox.lld.l_start;
	to->alock.l_len = (from->alock.lox.lld.l_len == 0) ? 0x7fffffff
						: from->alock.lox.lld.l_len;
	return 0;
}

int
reclocktonlm_unlockargs(from, to)
	struct reclock *from;
	nlm_unlockargs *to;
{
	int retval;

	if (from->cookie.n_len) {
		retval = obj_copy(&to->cookie, &from->cookie);
		if (retval == -1) return retval;
	}
#ifdef RISCOS_DEBUG
	to->alock.caller_name = xmalloc_debug (
		strlen(from->alock.caller_name)+1, __FILE__, __LINE__);
#else
	to->alock.caller_name = xmalloc(strlen(from->alock.caller_name)+1);
#endif
	if (to->alock.caller_name == NULL) {
		if (from->cookie.n_len) obj_free(&to->cookie);
		return -1;
	}
	strcpy (to->alock.caller_name, from->alock.caller_name);

	if (from->alock.fh.n_len) {
		retval = obj_copy(&to->alock.fh, &from->alock.fh);
		if (retval == -1) {
#ifdef RISCOS_DEBUG
			xfree_debug(&to->alock.caller_name,
				    __FILE__, __LINE__);
#else
			xfree(&to->alock.caller_name);
#endif
			if (from->cookie.n_len) obj_free(&to->cookie);
			return retval;
		      }
	}
	else {
		to->alock.fh.n_len = 0;
		to->alock.fh.n_bytes = 0;
	}

	if (from->alock.oh.n_len) {
		retval = obj_copy(&to->alock.oh, &from->alock.oh);
		if (retval == -1) {
			if (from->alock.fh.n_len) obj_free(&to->alock.fh);
#ifdef RISCOS_DEBUG
			xfree_debug(&to->alock.caller_name,
				    __FILE__, __LINE__);
#else
			xfree(&to->alock.caller_name);
#endif
			if (from->cookie.n_len) obj_free(&to->cookie);
			return retval;
		}
	}
	else {
		to->alock.oh.n_len = 0;
	}

	to->alock.svid = from->alock.lox.lld.l_pid;
	to->alock.l_offset = from->alock.lox.lld.l_start;
	to->alock.l_len = (from->alock.lox.lld.l_len == 0)
	  ? 0x7fffffff : from->alock.lox.lld.l_len;
	return 0;
}

int
reclocktonlm_testargs(from, to)
	struct reclock *from;
	nlm_testargs   *to;
{
	int retval;

	if (from->cookie.n_len) {
		retval = obj_copy(&to->cookie, &from->cookie);
		if (retval == -1) return retval;
	}
	to->exclusive = (from->lck.lox.lld.l_type == F_WRLCK) ? TRUE : FALSE;
#ifdef RISCOS_DEBUG
	to->alock.caller_name = xmalloc_debug (
		strlen(from->alock.caller_name)+1, __FILE__, __LINE__);
#else
	to->alock.caller_name = xmalloc(strlen(from->alock.caller_name)+1);
#endif
	if (to->alock.caller_name == NULL) return -1;
	strcpy (to->alock.caller_name, from->alock.caller_name);

	if (from->alock.fh.n_len) {
		retval = obj_copy(&to->alock.fh, &from->alock.fh);
		if (retval == -1) {
#ifdef RISCOS_DEBUG
			xfree_debug(&to->alock.caller_name,
				    __FILE__, __LINE__);
#else
			xfree(&to->alock.caller_name);
#endif
			if (from->cookie.n_len) obj_free(&to->cookie);
			return retval;
		}
	}
	else {
		to->alock.fh.n_len = 0;
		to->alock.fh.n_bytes = 0;
	}
	if (from->alock.oh.n_len) {
		retval = obj_copy(&to->alock.oh, &from->alock.oh);
		if (retval == -1) {
			if (from->alock.fh.n_len) obj_free(&to->alock.fh);
#ifdef RISCOS_DEBUG
			xfree_debug(&to->alock.caller_name,
				    __FILE__, __LINE__);
#else
			xfree(&to->alock.caller_name);
#endif
			if (from->cookie.n_len) obj_free(&to->cookie);
			return retval;
		}
	}
	else {
		to->alock.oh.n_len = 0;
	}

	to->alock.svid = from->alock.lox.lld.l_pid;
	to->alock.l_offset = from->alock.lox.lld.l_start;
	to->alock.l_len = (from->alock.lox.lld.l_len == 0)
	  ? 0x7fffffff : from->alock.lox.lld.l_len;
	return 0;
}

int
nlm_lockargstoreclock(from, to)
	nlm_lockargs   *from;
	struct reclock *to;
{
	int retval;

	if (from->cookie.n_len) {
		retval = obj_copy(&to->cookie, &from->cookie);
		if (retval == -1) return retval;
	      }
	to->block = (from->block) ? TRUE : FALSE;
	if (from->exclusive) {
		to->exclusive = TRUE;
		to->alock.lox.lld.l_type = F_WRLCK;
	} else {
		to->exclusive = FALSE;
		to->alock.lox.lld.l_type = F_RDLCK;
	}
#ifdef RISCOS_DEBUG
	to->alock.caller_name = xmalloc_debug (
		strlen(from->alock.caller_name)+1, __FILE__, __LINE__);
#else
	to->alock.caller_name = xmalloc(strlen(from->alock.caller_name)+1);
#endif
	if (to->alock.caller_name == NULL) {
		if (from->cookie.n_len) obj_free(&to->cookie);
		return -1;
	}
	strcpy (to->alock.caller_name, from->alock.caller_name);

	if (from->alock.fh.n_len) {
		retval = obj_copy(&to->alock.fh, &from->alock.fh);
		if (retval == -1) {
#ifdef RISCOS_DEBUG
			xfree_debug(&to->alock.caller_name,
				    __FILE__, __LINE__);
#else
			xfree(&to->alock.caller_name);
#endif
			if (from->cookie.n_len) obj_free(&to->cookie);
			return retval;
		}
	}
	else {
		to->alock.fh.n_len = 0;
		to->alock.fh.n_bytes = 0;
	}
	if (from->alock.oh.n_len) {
		retval = obj_copy(&to->alock.oh, &from->alock.oh);
		if (retval == -1) {
#ifdef RISCOS_DEBUG
			xfree_debug(&to->alock.caller_name,
				    __FILE__, __LINE__);
#else
			xfree(&to->alock.caller_name);
#endif
			if (from->cookie.n_len) obj_free(&to->cookie);
			return retval;
		}
	      }
	else {
		to->alock.oh.n_len = 0;
		to->alock.oh.n_bytes = 0;
	}

	to->alock.lox.lld.l_pid = from->alock.svid;
	to->alock.lox.lld.l_start = from->alock.l_offset;

	to->alock.lox.lld.l_len = (from->alock.l_len == 0)
		? 0x7fffffff : from->alock.l_len;

	/*
	 * Because the protocol requires some unique identifier to allow the
	 * remote machine to distinguish between lock requests AND the BSD 4.3
	 * flock record does NOT contain the system identifier maintained by
	 * System V, it is necessary to maintain the following field will be
	 * to make the requests unique.
	 */
	to->alock.lox.filocks.sysid=(long)nlm_transp->xp_raddr.sin_addr.s_addr;
	to->alock.lox.class = 0;
	return 0;
}

int
nlm_unlockargstoreclock(from, to)
	nlm_unlockargs *from;
	struct reclock *to;
{
	int retval;

	if (from->cookie.n_len) {
		retval = obj_copy(&to->cookie, &from->cookie);
		if (retval == -1) return retval;
	}
#ifdef RISCOS_DEBUG
	to->alock.caller_name = xmalloc_debug (
		strlen(from->alock.caller_name)+1, __FILE__, __LINE__);
#else
	to->alock.caller_name = xmalloc(strlen(from->alock.caller_name)+1);
#endif
	if (to->alock.caller_name == NULL) {
		if (from->cookie.n_len) obj_free(&to->cookie);
		return -1;
	}

	strcpy (to->alock.caller_name, from->alock.caller_name);

	if (from->alock.fh.n_len) {
		retval = obj_copy(&to->alock.fh, &from->alock.fh);
		if (retval == -1) {
#ifdef RISCOS_DEBUG
			xfree_debug(&to->alock.caller_name,
				    __FILE__, __LINE__);
#else
			xfree(&to->alock.caller_name);
#endif
			if (from->cookie.n_len) obj_free(&to->cookie);
			return retval;
		}
	}
	else {
		to->alock.fh.n_len = 0;
		to->alock.fh.n_bytes = 0;
	}

	if (from->alock.oh.n_len) {
		retval = obj_copy(&to->alock.oh, &from->alock.oh);
		if (retval == -1) {
#ifdef RISCOS_DEBUG
			xfree_debug(&to->alock.caller_name,
				    __FILE__, __LINE__);
#else
			xfree(&to->alock.caller_name);
#endif
			if (from->cookie.n_len) obj_free(&to->cookie);
			return retval;
		}
	}
	else {
		to->alock.oh.n_len = 0;
		to->alock.oh.n_bytes = 0;
	}

	to->alock.lox.lld.l_pid = from->alock.svid;
	to->alock.lox.lld.l_start = from->alock.l_offset;
	to->alock.lox.lld.l_len =
		(from->alock.l_len == 0) ? 0x7fffffff : from->alock.l_len;
	to->alock.lox.filocks.sysid=(long)nlm_transp->xp_raddr.sin_addr.s_addr;
	to->alock.lox.class = 0;
}

int
nlm_cancargstoreclock(from, to)
	nlm_cancargs   *from;
	struct reclock *to;
{
	int retval;

	if (from->cookie.n_len) {
		retval = obj_copy(&to->cookie, &from->cookie);
		if (retval == -1) return retval;
	      }

	to->block = from->block;
	if (from->exclusive) {
                to->exclusive = TRUE;
                to->alock.lox.lld.l_type = F_WRLCK; 
        } else {
                to->exclusive = FALSE;
                to->alock.lox.lld.l_type = F_RDLCK; 
        }
#ifdef RISCOS_DEBUG
	to->alock.caller_name = xmalloc_debug (
		strlen(from->alock.caller_name)+1, __FILE__, __LINE__);
#else
	to->alock.caller_name = xmalloc(strlen(from->alock.caller_name)+1);
#endif
	if (to->alock.caller_name == NULL) return -1;
	strcpy (to->alock.caller_name, from->alock.caller_name);

	if (from->alock.fh.n_len) {
		retval = obj_copy(&to->alock.fh, &from->alock.fh);
		if (retval == -1) {
#ifdef RISCOS_DEBUG
			xfree_debug(&to->alock.caller_name,
				    __FILE__, __LINE__);
#else
			xfree(&to->alock.caller_name);
#endif
			if (from->cookie.n_len) obj_free(&to->cookie);
			return retval;
		}
	}
	else {
		to->alock.fh.n_len = 0;
		to->alock.fh.n_bytes = 0;
	}

	if (from->alock.oh.n_len) {
		retval = obj_copy(&to->alock.oh, &from->alock.oh);
		if (retval == -1) {
			if (from->alock.fh.n_len) obj_free(&to->alock.fh);
#ifdef RISCOS_DEBUG
			xfree_debug(&to->alock.caller_name,
				    __FILE__, __LINE__);
#else
			xfree(&to->alock.caller_name);
#endif
			if (from->cookie.n_len) obj_free(&to->cookie);
			return retval;
		}
	}
	else {
		to->alock.oh.n_len = 0;
		to->alock.oh.n_bytes = 0;
	}
	to->alock.lox.lld.l_pid = from->alock.svid;
	to->alock.lox.lld.l_start = from->alock.l_offset;
	to->alock.lox.lld.l_len =
		(from->alock.l_len == 0) ? 0x7fffffff : from->alock.l_len;
	to->alock.lox.filocks.sysid=(long)nlm_transp->xp_raddr.sin_addr.s_addr;
	to->alock.lox.class = 0;
	return 0;
}

int
nlm_testargstoreclock(from, to)
	nlm_testargs   *from;
	struct reclock *to;
{
	int retval;

	if (from->cookie.n_len) {
		retval = obj_copy(&to->cookie, &from->cookie);
		if (retval == -1) return retval;
	}

	if (from->exclusive) {
		to->exclusive = TRUE;
		to->alock.lox.lld.l_type = F_WRLCK;
	} else {
		to->exclusive = FALSE;
		to->alock.lox.lld.l_type = F_RDLCK;
	}

#ifdef RISCOS_DEBUG
	to->alock.caller_name = xmalloc_debug (
		strlen(from->alock.caller_name)+1, __FILE__, __LINE__);
#else
	to->alock.caller_name = xmalloc(strlen(from->alock.caller_name)+1);
#endif
	if (to->alock.caller_name == NULL) {
		if (from->cookie.n_len) obj_free(&to->cookie);
		return -1;
	}
	strcpy (to->alock.caller_name, from->alock.caller_name);

	if (from->alock.fh.n_len) {
		retval = obj_copy(&to->alock.fh, &from->alock.fh);
		if (retval == -1) {
#ifdef RISCOS_DEBUG
			xfree_debug(&to->alock.caller_name,
				    __FILE__, __LINE__);
#else
			xfree(&to->alock.caller_name);
#endif
			if (from->cookie.n_len) obj_free(&to->cookie);
			return retval;
		}
	}
	else {
		to->alock.fh.n_len = 0;
		to->alock.fh.n_bytes = 0;
	}

	if (from->alock.oh.n_len) {
		retval = obj_copy(&to->alock.oh, &from->alock.oh);
		if (retval == -1) {
			if (from->alock.fh.n_len) obj_free(&to->alock.fh);
#ifdef RISCOS_DEBUG
			xfree_debug(&to->alock.caller_name,
				    __FILE__, __LINE__);
#else
			xfree(&to->alock.caller_name);
#endif
			if (from->cookie.n_len) obj_free(&to->cookie);
			return retval;
		}
	}
	else {
		to->alock.oh.n_len = 0;
		to->alock.oh.n_bytes = 0;
	}
	to->alock.lox.lld.l_pid = from->alock.svid;
	to->alock.lox.lld.l_start = from->alock.l_offset;
	to->alock.lox.lld.l_len =
		(from->alock.l_len == 0) ? 0x7fffffff : from->alock.l_len;
	to->alock.lox.filocks.sysid=(long)nlm_transp->xp_raddr.sin_addr.s_addr;
	to->alock.lox.class = 0;
	return 0;
}

int
nlm_testrestoremote_result(from, to)
	nlm_testres   *from;
	remote_result *to;
{
	int retval;

	if (from->cookie.n_len) {
		retval = obj_copy(&to->cookie, &from->cookie);
		if (retval == -1) return retval;
	      }
	to->stat.stat = from->stat.stat;
	to->stat.nlm_testrply_u.holder.exclusive = 
	  (from->stat.nlm_testrply_u.holder.exclusive) ? TRUE : FALSE;

	to->stat.nlm_testrply_u.holder.svid =
	  from->stat.nlm_testrply_u.holder.svid;

	retval = obj_copy(&to->stat.nlm_testrply_u.holder.oh,
		&from->stat.nlm_testrply_u.holder.oh);

	if (retval == -1) {
		if (from->cookie.n_len) obj_free(&to->cookie);
		return retval;
	}

	to->stat.nlm_testrply_u.holder.l_offset =
		from->stat.nlm_testrply_u.holder.l_offset;
	to->stat.nlm_testrply_u.holder.l_len =
		from->stat.nlm_testrply_u.holder.l_len;
	return 0;
}

int
nlm_restoremote_result(from, to)
	nlm_res *from;
	remote_result *to;
{
	int retval;

	if (from->cookie.n_len) {
		retval = obj_copy(&to->cookie, &from->cookie);
		if (retval == -1) return retval;
	      }
	to->stat.stat = from->stat.stat;
	return 0;
}

void
nlm_prog(Rqstp, Transp)
	struct svc_req *Rqstp;
	SVCXPRT *Transp;
{
	bool_t 			(*xdr_Argument)(), (*xdr_Result)();
	char 			*(*Local)();
	extern nlm_lockargs	*get_nlm_lockargs();
	extern nlm_unlockargs	*get_nlm_unlockargs();
	extern nlm_testargs	*get_nlm_testargs();
	extern nlm_cancargs	*get_nlm_cancargs();
	extern nlm_testres	*get_nlm_testres();
	extern nlm_res		*get_nlm_res();
	int			monitor_this_lock = 1;
	char 			*nlm_req, *nlm_rep;
	nlm_lockargs 		*nlm_lockargs_a;
	nlm_unlockargs 		*nlm_unlockargs_a;
	nlm_testargs 		*nlm_testargs_a;
	nlm_cancargs 		*nlm_cancargs_a;
	nlm_testres		*nlm_testres_a;
	nlm_res			*nlm_res_a;
	struct reclock  	*req;
	remote_result 		*reply;
	int 			oldmask, retval;
#ifdef RISCOS_DEBUG
	int inuse;
#endif

	if (debug) {
		printf("NLM_PROG+++ version %d proc %d\n",
			Rqstp->rq_vers, Rqstp->rq_proc);
		pr_all();
	}

	oldmask = sigblock (1 << (SIGALRM -1));
	nlm_transp = Transp;		/* export the transport handle */

	switch (Rqstp->rq_proc) {
	case NULLPROC:
		svc_sendreply(Transp, xdr_void, NULL);
		(void) sigsetmask(oldmask);
		return;

	case DEBUG_ON:
		debug = 2;
		svc_sendreply(Transp, xdr_void, NULL);
		(void) sigsetmask(oldmask);
		return;

	case DEBUG_OFF:
		debug = 0;
		svc_sendreply(Transp, xdr_void, NULL);
		(void) sigsetmask(oldmask);
		return;

	case NLM_TEST:
		xdr_Argument = xdr_nlm_testargs;
		xdr_Result = xdr_nlm_testres;
		Local = (char *(*)()) proc_nlm_test;

		if ((nlm_testargs_a = get_nlm_testargs()) == NULL) {
			printf("rpc.lockd: unable to allocate space for nlm_req.\n");
			(void) sigsetmask(oldmask);
			return;
		}
		nlm_req = (char *) nlm_testargs_a;
		break;

	case NLM_LOCK:
		xdr_Argument = xdr_nlm_lockargs;
		xdr_Result = xdr_nlm_res;
		Local = (char *(*)()) proc_nlm_lock;

		if ((nlm_lockargs_a = get_nlm_lockargs()) == NULL) {
			printf("rpc.lockd: unable to allocate space for nlm_req.\n");
			(void) sigsetmask(oldmask);
			return;
		}
		nlm_req = (char *) nlm_lockargs_a;
		break;

	case NLM_CANCEL:
		xdr_Argument = xdr_nlm_cancargs;
		xdr_Result = xdr_nlm_res;
		Local = (char *(*)()) proc_nlm_cancel;

		if ((nlm_cancargs_a = get_nlm_cancargs()) == NULL) {
			printf("rpc.lockd: unable to allocate space for nlm_req.\n");
			(void) sigsetmask(oldmask);
			return;
		}
		nlm_req = (char *) nlm_cancargs_a;
		break;

	case NLM_UNLOCK:
		xdr_Argument = xdr_nlm_unlockargs;
		xdr_Result = xdr_nlm_res;
		Local = (char *(*)()) proc_nlm_unlock;

		if ((nlm_unlockargs_a = get_nlm_unlockargs()) == NULL) {
			printf("rpc.lockd: unable to allocate space for nlm_req.\n");
			(void) sigsetmask(oldmask);
			return;
		}
		nlm_req = (char *) nlm_unlockargs_a;
		break;

	case NLM_TEST_MSG:
		xdr_Argument = xdr_nlm_testargs;
		xdr_Result = xdr_void;
		Local = (char *(*)()) proc_nlm_test_msg;

		if ((nlm_testargs_a = get_nlm_testargs()) == NULL) {
			printf("rpc.lockd: unable to allocate space for nlm_req.\n");
			(void) sigsetmask(oldmask);
			return;
		}
		nlm_req = (char *) nlm_testargs_a;
		break;

	case NLM_LOCK_RECLAIM:
	case NLM_LOCK_MSG:
		xdr_Argument = xdr_nlm_lockargs;
		xdr_Result = xdr_void;
		Local = (char *(*)()) proc_nlm_lock_msg;

		if ((nlm_lockargs_a = get_nlm_lockargs()) == NULL) {
			printf("rpc.lockd: unable to allocate space for nlm_req.\n");
			(void) sigsetmask(oldmask);
			return;
		}
		nlm_req = (char *) nlm_lockargs_a;
		break;

	case NLM_CANCEL_MSG:
		xdr_Argument = xdr_nlm_cancargs;
		xdr_Result = xdr_void;
		Local = (char *(*)()) proc_nlm_cancel_msg;

		if ((nlm_cancargs_a = get_nlm_cancargs()) == NULL) {
			printf("rpc.lockd: unable to allocate space for nlm_req.\n");
			(void) sigsetmask(oldmask);
			return;
		}
		nlm_req = (char *) nlm_cancargs_a;
		break;

	case NLM_UNLOCK_MSG:
		xdr_Argument = xdr_nlm_unlockargs;
		xdr_Result = xdr_void;
		Local = (char *(*)()) proc_nlm_unlock_msg;

		if ((nlm_unlockargs_a = get_nlm_unlockargs()) == NULL) {
			printf("rpc.lockd: unable to allocate space for nlm_req.\n");
			(void) sigsetmask(oldmask);
			return;
		}
		nlm_req = (char *) nlm_unlockargs_a;
		break;

	case NLM_TEST_RES:
		xdr_Argument = xdr_nlm_testres;
		xdr_Result = xdr_void;
		Local = (char *(*)()) proc_nlm_test_res;

		if ((nlm_testres_a = get_nlm_testres()) == NULL) {
			printf("rpc.lockd: unable to allocate space for nlm_req.\n");
			(void) sigsetmask(oldmask);
			return;
		}
		nlm_rep = (char *) nlm_testres_a;
		break;

	case NLM_LOCK_RES:
		xdr_Argument = xdr_nlm_res;
		xdr_Result = xdr_void;
		Local = (char *(*)()) proc_nlm_lock_res;

		if ((nlm_res_a = get_nlm_res()) == NULL) {
			printf("rpc.lockd: unable to allocate space for nlm_req.\n");
			(void) sigsetmask(oldmask);
			return;
		}
		nlm_rep = (char *) nlm_res_a;
		break;

	case NLM_CANCEL_RES:
		xdr_Argument = xdr_nlm_res;
		xdr_Result = xdr_void;
		Local = (char *(*)()) proc_nlm_cancel_res;

		if ((nlm_res_a = get_nlm_res()) == NULL) {
			printf("rpc.lockd: unable to allocate space for nlm_req.\n");
			(void) sigsetmask(oldmask);
			return;
		}
		nlm_rep = (char *) nlm_res_a;
		break;

	case NLM_UNLOCK_RES:
		xdr_Argument = xdr_nlm_res;
		xdr_Result = xdr_void;
		Local = (char *(*)()) proc_nlm_unlock_res;

		if ((nlm_res_a = get_nlm_res()) == NULL) {
			printf("rpc.lockd: unable to allocate space for nlm_req.\n");
			(void) sigsetmask(oldmask);
			return;
		}
		nlm_rep = (char *) nlm_res_a;
		break;

	case NLM_SHARE:
	case NLM_UNSHARE:
		if (Rqstp->rq_vers != NLM_VERSX) {
			svcerr_noproc(Transp);
			(void) sigsetmask(oldmask);
			return;
		}
		proc_nlm_share(Rqstp, Transp);
		(void) sigsetmask(oldmask);
		return;

	case NLM_NM_LOCK:
		if (Rqstp->rq_vers != NLM_VERSX) {
			svcerr_noproc(Transp);
			(void) sigsetmask(oldmask);
			return;
		}
		Rqstp->rq_proc = NLM_LOCK; /* fake it */
		monitor_this_lock = 0;
		xdr_Argument = xdr_nlm_lockargs;
		xdr_Result = xdr_void;
		Local = (char *(*)()) proc_nlm_lock;

		if ((nlm_lockargs_a = get_nlm_lockargs()) == NULL) {
			printf("rpc.lockd: unable to allocate space for nlm_req.\n");
			(void) sigsetmask(oldmask);
			return;
		}
		nlm_req = (char *) nlm_lockargs_a;
		break;

	case NLM_FREE_ALL:
		if (Rqstp->rq_vers != NLM_VERSX) {
			svcerr_noproc(Transp);
		}
		else {
			proc_nlm_freeall(Rqstp, Transp);
		}
		(void) sigsetmask(oldmask);
		return;

	default:
		svcerr_noproc(Transp);
		(void) sigsetmask(oldmask);
		return;
	}

	if (Rqstp->rq_proc != NLM_LOCK_RES &&
	    Rqstp->rq_proc != NLM_CANCEL_RES &&
	    Rqstp->rq_proc != NLM_UNLOCK_RES &&
	    Rqstp->rq_proc != NLM_TEST_RES) {
		/*
		* Handle a network lock manager REQUEST message
		*/
		if ((req = get_reclock()) != NULL) {
			if (!svc_getargs(Transp, xdr_Argument, nlm_req)) {
				svcerr_decode(Transp);
#ifdef RISCOS_DEBUG
				xfree_debug(&nlm_req, __FILE__, __LINE__);
				xfree_debug(&req, __FILE__, __LINE__);
#else
				xfree(&nlm_req);
				xfree(&req);
#endif
				(void) sigsetmask(oldmask);
				return;
			}

			switch (Rqstp->rq_proc) {
			case NLM_TEST:
			case NLM_TEST_MSG:
				retval = nlm_testargstoreclock(
					  (struct nlm_testargs *)nlm_req, req);
				break;

			case NLM_LOCK:
			case NLM_LOCK_MSG:
			case NLM_LOCK_RECLAIM:
			case NLM_NM_LOCK:
				retval = nlm_lockargstoreclock(
				 (struct nlm_lockargs *)nlm_req, req);
				break;

			case NLM_CANCEL:
			case NLM_CANCEL_MSG:
				retval = nlm_cancargstoreclock(
				 (struct nlm_cancargs *)nlm_req, req);
				break;

			case NLM_UNLOCK:
			case NLM_UNLOCK_MSG:
				retval = nlm_unlockargstoreclock(
				 (struct nlm_unlockargs *)nlm_req, req);
				break;

			default:
				retval = 0;
				break;
			}

			if (retval == -1) {
				/*
				 * Translation error from nlm_args to reclock!
				 * Hence the reclock 'req' is assumed to NOT
				 * have been allocated. This leaves the
				 * nlm_req arguments to be deallocated.
				 */
				goto xlate_nlm_to_reclock;
			}

			if (debug == 3) {
				if (fwrite(&nlm, sizeof (int), 1, fp) == 0)
					fprintf(stderr, "fwrite nlm error\n");
				if (fwrite(&Rqstp->rq_proc,sizeof(int),
					   1, fp) == 0)	fprintf(stderr,
						"fwrite nlm_proc error\n");
				printf("range[%d, %d]\n",
			req->lck.lox.lld.l_start, req->lck.lox.lld.l_len);
				(void) fflush(fp);
			}

			if (map_klm_nlm(req) == -1) {
				goto request_map_error;
			}

			if (grace_period >0 && !(req->reclaim)) {
				if (debug)
			printf("during grace period, please retry later\n");

				nlm_reply(Rqstp->rq_proc, &res_grace, req);
				release_nlm_args(Rqstp->rq_proc, nlm_req);
				req->rel = 1;
				release_reclock(req);
				(void) sigsetmask(oldmask);
				return;
			}
			if (grace_period >0 && debug)
				printf("accept reclaim request(%x)\n", req);

			if (monitor_this_lock &&
			    (Rqstp->rq_proc == NLM_LOCK ||
			     Rqstp->rq_proc == NLM_LOCK_MSG ||
			     Rqstp->rq_proc == NLM_LOCK_RECLAIM)) {

				if (add_mon(req, 1) == -1) {
				        /* Failed to talk with status monitor*/
					req->rel = 1;
					release_reclock(req);

					release_nlm_args(Rqstp->rq_proc,
							 nlm_req);

					fprintf(stderr,
		"Request discarded due to some status monitor problem\n");
					(void) sigsetmask(oldmask);
					return;
				}
			}

			(*Local)(req);
			req->rel = 1;
			release_reclock(req);

			/*
			 * The old code had a check here that if the request
			 * caused nlm to call klm back then we should release
			 * the nlm_req arguments record. aka:
			 * if (req->rel) then switch stmt that released args
			 *
			 * This was changed to ALWAYS release the args since
			 * they are never reused on retransmission by the
			 * external timer procedure OR stored in the request
			 * queue entry. This was just one of many standard
			 * variety storage leak bug(s)!
			 */
			release_nlm_args(Rqstp->rq_proc, nlm_req);
		} else {
		         /*
			  * Failed allocating 'req' so return nolock status
			  * NOTE: This is BOGUS using the invalid 'req' value
			  * to send the reply message!
			  */
			nlm_reply((int) Rqstp->rq_proc, &res_nolock, req);
		}
	        goto exit_point;
	} else {
		/*
		 * Handle network lock manager REPLY/RESPONSE messages here!
		 */
		if ((reply = get_res()) != NULL) {
			if (!svc_getargs(Transp, xdr_Argument, nlm_rep)) {
				svcerr_decode(Transp);
#ifdef RISCOS_DEBUG
				xfree_debug(&nlm_rep, __FILE__, __LINE__);
				xfree_debug(&reply, __FILE__, __LINE__);
#else
				xfree(&nlm_rep);
				xfree(&reply);
#endif
				(void) sigsetmask(oldmask);
				return;
			}

			switch (Rqstp->rq_proc) {
			case NLM_TEST_RES:
				retval = nlm_testrestoremote_result(nlm_rep,
							reply);
				break;

			case NLM_LOCK_RES:
			case NLM_CANCEL_RES:
			case NLM_UNLOCK_RES:
				retval = nlm_restoremote_result(nlm_rep,reply);
				break;

			default:
				retval = 0;
				break;
			}

			if (retval == -1) {
				goto xlate_remote_result;
			}

			if (debug == 3) {
				if (fwrite(&nlm, sizeof (int), 1, fp) == 0)
				  fprintf(stderr,"fwrite nlm_reply error\n");
				if (fwrite(&Rqstp->rq_proc, sizeof (int),
					1, fp) == 0)
					fprintf(stderr,
					  "fwrite nlm_reply_proc error\n");

				(void) fflush(fp);
			}
			if (debug) {
				printf("msg reply(%d) to procedure(%d)\n",
					reply->lstat, Rqstp->rq_proc);
			}

			(*Local)(reply);
			/*
			 * Release the network lock manager reply parameters
			 */
			release_nlm_reply(Rqstp->rq_proc, nlm_rep);
		}
	}
	goto exit_point;

xlate_nlm_to_reclock:
	/*
	 * Translation error from nlm_req to a reclock.
	 * Release the space associated with the nlm request arguments.
	 *
	 * NOTE: You can NOT assume that reclock 'req' has been initialized
	 * to contain anything useful since the translation probably failed
	 * due to storage allocation failure! Hence the call to nlm_reply
	 * below is BOGUS!
	 */
	nlm_reply((int) Rqstp->rq_proc, &res_nolock, req);
	release_nlm_args(Rqstp->rq_proc, nlm_req);

	printf("rpc.lockd: nlm_prog: Xlate error from nlm_req to reclock\n");
	goto exit_point;

xlate_remote_result:
	/*
	 * Translation error on handling the creation of the reply message.
	 * Specifically in translating a nlm_rep(ly) to a network reply.
	 * Similar to the above cases we assume the remote_result 'reply'
	 * data structure was NOT allocated. Hence we only have to release the
	 * space associated with the nlm_rep(ly) arguments.
	 *
	 * NOTE: You can NOT assume that the reclock 'req' has been initialized
	 * to contain anything useful since the translation failed probably
	 * due to storage allocation failure! Hence the call to nlm_reply
	 * below is BOGUS!
	 */
	nlm_reply((int) Rqstp->rq_proc, &res_nolock, req);
	release_nlm_reply(Rqstp->rq_proc, nlm_rep);

	printf("rpc.lockd: nlm_prog: Xlate error from nlm_rep to net reply\n");
	goto exit_point;

request_map_error:
	/*
	 * Failed to map the request into the klm specific parameters.
	 * So send the standard no lock reply and release the space
	 * associate with the request msg.
	 *
	 * NOTE: Here the call to nlm_reply below maybe ok since req
	 * would only contain invalid string addresses on storage allocation
	 * failure! This is still BOGUS!
	 */
	nlm_reply((int) Rqstp->rq_proc, &res_nolock, req);
	release_nlm_args(Rqstp->rq_proc, nlm_req);

exit_point:

#ifdef RISCOS_DEBUG
	inuse = xcheck_debug();
	if (inuse > 0)
	  printf("nlm_prog: Exit: Remaining node ct= %d\n", inuse);
#endif
	if (debug)
		printf("EXITING FROM NLM_PROG...\n");

	(void) sigsetmask(oldmask);
	return;
}

int
release_nlm_args(proc, nlm_req)
int proc;
char *nlm_req;
{
	switch (proc) {
	case NLM_TEST:
	case NLM_TEST_MSG:
		release_nlm_testargs(nlm_req);
		break;

	case NLM_LOCK:
	case NLM_LOCK_MSG:
	case NLM_LOCK_RECLAIM:
	case NLM_NM_LOCK:
		release_nlm_lockargs(nlm_req);
		break;

	case NLM_CANCEL:
	case NLM_CANCEL_MSG:
		release_nlm_cancargs(nlm_req);
		break;

	case NLM_UNLOCK:
	case NLM_UNLOCK_MSG:
		release_nlm_unlockargs(nlm_req);
		break;
	}
return;
}

int
release_nlm_reply(proc, nlm_rep)
int proc;
char *nlm_rep;
{
	switch (proc) {
	case NLM_TEST_RES:
		(void)release_nlm_testres((nlm_testres *)nlm_rep);
		break;

	case NLM_LOCK_RES:
	case NLM_CANCEL_RES:
	case NLM_UNLOCK_RES:
		(void)release_nlm_res((nlm_res *)nlm_rep);
		break;
	}
	return;
}
