/*
 * |-----------------------------------------------------------|
 * | 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_libr.c,v 1.5.2.1 92/06/24 13:50:40 marker Exp $"

/*
 * This file contains basic utility procedures used to initialize,
 * map various parameters in record lock structures for both local and
 * remote cases and provide some general procedures for printing various
 * data structures for debugging support.
 */
#include <stdio.h>
#include <sys/param.h>
#include <memory.h>
#include <sys/file.h>
#include <sys/dirent.h>
#include "prot_lock.h"
#include "prot_time.h"

char hostname[MAXNAMLEN+1];		/* for generating oh */

int pid;				/* id for monitor usage */
int host_len;				/* for generating oh */
int lock_len;
int res_len;
int msg_len;
int grace_period;
int cookie;				/* monitonically increasing # */

remote_result res_nolock, res_working, res_grace;

extern lm_vnode *fh_q;
extern struct filock *sleeplcks;
extern struct reclock *sleeplcks_reclox;
extern msg_entry *msg_q;
extern int debug, used_reclock;

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

init()
{
	/* used to generate owner handle */
	(void) gethostname(hostname, MAXNAMLEN+1);
	host_len = strlen(hostname)+1;

	msg_len = sizeof (msg_entry);
	lock_len = sizeof (struct reclock);
	res_len = sizeof (remote_result);
	pid = getpid(); /* used to generate return id for status monitor */
	res_nolock.lstat = nolocks;
	res_working.lstat = blocking;
	res_grace.lstat = grace;
	grace_period = LM_GRACE;
	cancel_mon();
}

/*
 * map input (from kernel) to lock manager internal structure
 * returns -1 if cannot allocate memory; returns 0 otherwise
 */
int
map_kernel_klm(a)
	reclock *a;
{
	int retval;

	/*
	 * common code shared between map_kernel_klm and map_klm_nlm op
	 */
	if (a->lck.lox.lld.l_type == F_WRLCK) {
		a->lck.op = LOCK_EX;
	} else if (a->lck.lox.lld.l_type == F_RDLCK) {
		a->lck.op = LOCK_SH;
	}

	if (a->block == FALSE)
		a->lck.op = a->lck.op | LOCK_NB;
	if (a->lck.lox.lld.l_len > MAXLEN) {
		fprintf(stderr, " len(%d) greater than max len(%d)\n",
			a->lck.lox.lld.l_len, MAXLEN);
		a->lck.lox.lld.l_len = MAXLEN;
	}

	/*
	 * generate svid holder
	 */
	if (!a->lck.lox.lld.l_pid)
		a->lck.lox.lld.l_pid = getpid();
	a->lck.svid = a->lck.lox.lld.l_pid;

	/*
	 * owner handle == (hostname, pid); We cannot generate owner handle
	 * use obj_alloc because additional pid attached at the end
	 */
	a->lck.oh_len = host_len + sizeof (int);

#ifdef RISCOS_DEBUG
	a->lck.oh_bytes = xmalloc_debug(a->lck.oh_len, __FILE__, __LINE__);
#else
	a->lck.oh_bytes = xmalloc(a->lck.oh_len);
#endif
	if (a->lck.oh_bytes == NULL) {
		a->lck.oh_len = 0;
		return (-1);
	}

	(void) strcpy(a->lck.oh_bytes, hostname);
	memcpy(&a->lck.oh_bytes[host_len], (char *) &a->lck.lox.lld.l_pid,
		sizeof (int));

	/*
	 * generate cookie by a monotonic increasing set of numbers
	 */
	cookie++;
	retval = obj_alloc(&a->cookie, (char *) &cookie, sizeof (int));

	if (retval == -1) { /* failed so do some cleanup */
		obj_free(&a->lck.oh);
		return retval;
	}

	/*
	 * Allocate the string bodies and copy the host name string
	 * in the local call case.
	 */
#ifdef RISCOS_DEBUG
	a->lck.clnt_name = xmalloc_debug(host_len, __FILE__, __LINE__);
#else
	a->lck.clnt_name = xmalloc(host_len);
#endif
	if (a->lck.clnt_name == NULL) {
		obj_free(&a->lck.oh);
		return (-1);
       }
	(void) strcpy(a->lck.clnt_name, hostname);

#ifdef RISCOS_DEBUG
	a->lck.caller_name = xmalloc_debug(host_len,__FILE__, __LINE__);
#else
	a->lck.caller_name = xmalloc(host_len);
#endif

	if (a->lck.caller_name == NULL) {
#ifdef RISCOS_DEBUG
	  xfree_debug(&a->lck.clnt_name,__FILE__, __LINE__);
#else
	  xfree(&a->lck.clnt_name);
#endif
	  obj_free(&a->lck.oh);
	  return (-1);
	}
	(void) strcpy(a->lck.caller_name, hostname);
	return 0;
}

/*
 * nlm map input from klm to lock manager internal structure
 * return -1, if cannot allocate memory!
 * returns 0, otherwise
 */
int
map_klm_nlm(a)
	reclock *a;
{
	int str_len;

	/*
	 * common code shared between map_kernel_klm and map_klm_nlm
	 */
	if (a->lck.lox.lld.l_type == F_WRLCK) {
		a->lck.op = LOCK_EX;
	} else if (a->lck.lox.lld.l_type == F_RDLCK) {
		a->lck.op = LOCK_SH;
	}
	if (a->block == FALSE)
		a->lck.op = a->lck.op | LOCK_NB;

	/*
	 * generate svid holder
	 */
	if (!a->lck.lox.lld.l_pid)
		a->lck.lox.lld.l_pid = getpid();
	a->lck.svid = a->lck.lox.lld.l_pid;

	a->lck.l_offset = a->lck.lox.lld.l_start;
	a->lck.l_len = a->lck.lox.lld.l_len;

 	/*
	 * In klm to nlm transformation calls the client name to whom to
	 * send the response is the caller name in the request and NOT the
	 * host name in the responses that are returned to the local kernel.
	 */
#ifdef RISCOS_DEBUG
	a->lck.server_name = xmalloc_debug(host_len,__FILE__,__LINE__);
#else
	a->lck.server_name = xmalloc(host_len);
#endif
	if (a->lck.server_name == NULL) {
		return (-1);
	}
	(void) strcpy(a->lck.server_name, hostname);

	str_len = strlen(a->lck.caller_name)+1;
#ifdef RISCOS_DEBUG
	a->lck.clnt_name = xmalloc_debug(str_len,__FILE__,__LINE__);
#else
	a->lck.clnt_name = xmalloc(str_len);
#endif
	if (a->lck.clnt_name == NULL) {
#ifdef RISCOS_DEBUG
		xfree_debug(&a->lck.server_name,__FILE__,__LINE__);
#else
		xfree(&a->lck.server_name);
#endif
		return (-1);
	}
	(void) strcpy(a->lck.clnt_name, a->lck.caller_name);
	return 0;
}

int
pr_oh(a)
	netobj *a;
{
	int i;
	int j;
	unsigned p = 0;

	if (a->n_len - sizeof (int) > 4 )
		j = 4;
	else
		j = a->n_len - sizeof (int);

	/*
	 * only print out part of oh
	 */
	for (i = 0; i< j; i++) {
		printf("%c", a->n_bytes[i]);
	}
	for (i = a->n_len - sizeof (int); i< a->n_len; i++) {
		p = (p << 8) | (((unsigned)a->n_bytes[i]) & 0xff);
	}
	printf("%u", p);
}

int
pr_fh(a)
	netobj *a;
{
	int i;

	for (i = 0; i< a->n_len; i++) {
		printf("%02x", (a->n_bytes[i] & 0xff));
	}
}

int
pr_lock(a)
	reclock *a;
{
	if (a != NULL) {
		printf("(%x), oh= ", a);
		pr_oh(&a->lck.oh);
		printf(", svr= %s\n", a->lck.server_name);
		printf("fh= ");
		pr_fh(&a->lck.fh);
		printf("\n");

		if (a->block)
			printf("block=TRUE ");
		else
			printf("block=FALSE ");

		if (a->exclusive)
			printf("exclusive=TRUE ");
		else
			printf("exclusive=FALSE ");

		printf(
	     "rel=%d w_flag=%d type=%d pid=%d class=%d granted=%d LockID=%d\n",
		a->rel, a->w_flag, a->lck.lox.lld.l_type, a->lck.lox.lld.l_pid,
		a->lck.lox.class, a->lck.lox.granted, a->lck.lox.LockID);

		printf("op= ");
		pr_op(a->lck.op);
		printf("ranges= [%d, %d)\n",
			a->lck.lox.lld.l_start,
		        a->lck.lox.lld.l_start + a->lck.lox.lld.l_len);
	} else {
		printf("RECLOCK is NULL.\n");
	}
}

int
pr_op(op)
	int op;
{
	switch (op) {

	case 1: /* KLM_TEST */
	  printf("KLM_TEST(1) ");
	  break;
	case 2: /* KLM_LOCK */
	  printf("KLM_LOCK(2) ");
	  break;

	case 3: /* KLM_CANCEL */
	  printf("KLM_CANCEL(3) ");
	  break;

	case 4: /* KLM_UNLOCK */
	  printf("KLM_UNLOCK(4) ");
	  break;

	default:
	  printf("%d ", op);
	  break;
	}
}

int
pr_vfilock(a)
        struct filock *a;
{
        if (a != NULL) {
                printf("(%x), ", a);
                printf(" type=%d, whence=%d, pid=%d, ",
                        a->set.l_type, a->set.l_whence, a->set.l_pid);
                printf(
	     "ranges= [%d, %d) wakeflg=%d stat.blk.sysid=%d stat.blk.pid=%d\n",
             a->set.l_start, a->set.l_start + a->set.l_len, a->stat.wakeflg,
	     a->stat.blk.sysid, a->stat.blk.pid);
        } else {
                printf("VFILOCK is NULL.\n");
        }
}

pr_all()
{
	struct reclock *tf;
	struct lm_vnode *fl;
	struct filock *ff;
	msg_entry *msgp;
	int i, ii;

	if (debug < 2)
		return;

	/*
	 * print msg queue
	 */
	if (msg_q != NULL) {
		printf("***** MSG QUEUE *****\n");
		msgp= msg_q;
		while (msgp != NULL) {
			printf("(%x) : ", msgp->req);
			printf(" (%x, ", msgp->req);
			if (msgp->reply != NULL)
				printf(" lstat =%d), ", msgp->reply->lstat);
			else
				printf(" NULL), ");
			msgp = msgp->nxt;
		}
		printf("\n");
	}
	else
		printf("***** NO MSG IN MSG QUEUE *****\n");

	/*
	 * print fh_q
	 */
	if (fh_q != NULL) {
		printf("\n***** FILE HANDLE LIST *****");
		for (fl = fh_q; fl; fl = fl->next) {
			if (fl->filocks != NULL) {
                                printf("\n***** V_FILOCKS : %x *****\n",
                                        fl);
                                for (ff = fl->filocks; ff; ff = ff->next) {
                                        pr_vfilock(ff);
                                }
                        } else
                                printf("\n***** NO V_FILOCKS : %x****",
                                        fh_q);
			if (fl->reclox != NULL) {
				printf("\n***** RECLOX LOCKS : %x *****\n", fl);
				for (tf = fl->reclox; tf; tf = tf->next) {
					pr_lock(tf);
				}
			} else
				printf("\n***** NO RECLOX LOCKS : %x\n****",
					fl);
		}
	}
	else
		printf("\n***** NO FILE HANDLE STRUCT ****\n");
	/* 
         * print sleeplcks 
         */ 
        if (sleeplcks != NULL) { 
                printf("\n***** SLEEP LCK LIST *****"); 
                for (ff = sleeplcks; ff; ff = ff->next) { 
                        pr_vfilock(ff); 
		}
	} else
                printf("\n***** NO SLEEPLCKS : %x****\n", sleeplcks); 

	/*
         * print sleeplcks_reclox
         */
        if (sleeplcks_reclox != NULL) {
                printf("\n***** SLEEPLCKS_RECLOX LIST *****");
                for (tf = sleeplcks_reclox; tf; tf = tf->next) {
                        pr_lock(tf);
                }
        } else
                printf("\n***** NO SLEEPLCKS_RECLOX : %x****\n", 
			sleeplcks_reclox);

	printf("used_reclock=%d\n", used_reclock);
	(void) fflush(stdout);
}

up(x)
	int x;
{
	return ((x % 2 == 1) || (x %2 == -1));
}

kill_process(a)
	reclock *a;
{
	fprintf(stderr, "kill process (%d)\n", a->lck.lox.lld.l_pid);
	(void) kill(a->lck.lox.lld.l_pid, SIGLOST);
}
