/*
 *	Namespace emulation for Unix and Windows
 *
 *	This header is included by device drivers and libns itself.
 *	Programs wishing to use the emulation should be compiled
 *	with -DUSENS.
 */

typedef struct Block	Block;
typedef struct Chan	Chan;
typedef struct Cname	Cname;
typedef struct Dev	Dev;
typedef struct DevConf	DevConf;
typedef struct Dirtab	Dirtab;
typedef struct Fgrp	Fgrp;
typedef struct Mntcache Mntcache;
typedef struct Mount	Mount;
typedef struct Mntrpc	Mntrpc;
typedef struct Mntwalk	Mntwalk;
typedef struct Mnt	Mnt;
typedef struct Mhead	Mhead;
typedef struct Nsconf	Nsconf;
typedef struct Osenv	Osenv;
typedef struct Pgrp	Pgrp;
typedef struct Pointer	Pointer;
typedef struct Proc	Proc;
typedef struct Procs	Procs;
typedef struct Rb	Rb;
typedef struct Queue	Queue;
typedef struct Ref	Ref;
typedef struct Rendez	Rendez;
typedef struct Session	Session;
typedef struct Walkqid Walkqid;
typedef int    Devgen(Chan*, char*, Dirtab*, int, int, Dir*);

#include <mdproc.h>
#include <mddir.h>
#include <mdfloat.h>
#include <fcall.h>

#define sleep rendsleep
#define wakeup rendwakeup

/*
 *	Manifest constants
 */
enum
{
	MAXROOT		= 128,	/* Maximum root pathname len of devfs-* */
	NUMSIZE		= 11,
	MAXDEVCMD 	= 128,		/* Maximum size for command */
	KNAMELEN = 28,
};

/*
 * Access types in namec & channel flags
 */
enum
{
	Aaccess,			/* as in access, stat */
	Atodir,				/* as in chdir */
	Aopen,				/* for i/o */
	Amount,				/* to be mounted upon */
	Acreate,			/* file is to be created */
	Aremove,			/* will be removed by caller */
	Abind,				/* will be bound somewhere by caller */

	COPEN	= 0x0001,		/* for i/o */
	CMSG	= 0x0002,		/* the message channel for a mount */
	CCEXEC	= 0x0008,		/* close on exec */
	CFREE	= 0x0010,		/* not in use */
	CRCLOSE	= 0x0020,		/* remove on close */
	CCACHE	= 0x0080		/* client cache */
};

/*
 *	Process creation
 */
enum
{
	NSPDUP	= 1 << 0,
};

struct Ref
{
	Lock l;
	long	ref;
};

struct Rendez
{
	Lock	l;
	Proc*	p;
};

struct Cname
{
	Ref	r;
	int	alen;			/* allocated length */
	int	len;			/* strlen(s) */
	char	*s;
};

struct Chan
{
	Ref	r;
	Chan*	next;			/* allocation */
	Chan*	link;
	vlong	offset;			/* in file */
	ushort	type;
	ulong	dev;
	ushort	mode;			/* read/write */
	ushort	flag;
	Qid	qid;
	int	fid;			/* for devmnt */
	ulong	iounit;	/* chunk size for i/o; 0==default */
	Mhead*	umh;			/* mount point that derived Chan */
	Chan*	umc;			/* channel in union; held for union read */
	QLock	umqlock;		/* serialize unionreads */
	int	uri;			/* union read index */
	int	dri;			/* dirread index */
	ulong	mountid;
	Mntcache *mcp;			/* Mount cache pointer */
	Mnt	*mux;			/* Mnt for clients using me for messages */
	union {
		void*	aux;
		Mnt*	mntptr;		/* for devmnt */
	} u;
	Chan*	mchan;			/* channel to mounted server */
	Qid	mqid;			/* qid of root of mount point */
	Session	*session;
	Cname	*name;
};

struct Dev
{
	int	dc;
	char*	name;

	void	(*reset)(void);
	void	(*init)(void);
	Chan*	(*attach)(char*);
	Walkqid*	(*walk)(Chan*, Chan*, char**, int);
	int	(*stat)(Chan*, uchar*, int);
	Chan*	(*open)(Chan*, int);
	void	(*create)(Chan*, char*, int, ulong);
	void	(*close)(Chan*);
	long	(*read)(Chan*, void*, long, vlong);
	Block*	(*bread)(Chan*, long, ulong);
	long	(*write)(Chan*, void*, long, vlong);
	long	(*bwrite)(Chan*, Block*, ulong);
	void	(*remove)(Chan*);
	int	(*wstat)(Chan*, uchar*, int);
	void	(*power)(int);	/* power mgt: power(1) => on, power (0) => off */
	int	(*config)(int, char*, DevConf*);
};

enum
{
	BINTR		=	(1<<0),
	BFREE		=	(1<<1),
	BMORE		=	(1<<2)		/* continued in next block */
};

struct Block
{
	Block*	next;
	Block*	list;
	uchar*	rp;			/* first unconsumed byte */
	uchar*	wp;			/* first empty byte */
	uchar*	lim;			/* 1 past the end of the buffer */
	uchar*	base;			/* start of the buffer */
	void	(*free)(Block*);
};
#define BLEN(s)	((s)->wp - (s)->rp)
#define BALLOC(s) ((s)->lim - (s)->base)

struct Dirtab
{
	char	name[KNAMELEN];
	Qid	qid;
	vlong length;
	long	perm;
};

struct Walkqid
{
	Chan	*clone;
	int	nqid;
	Qid	qid[1];
};

enum
{
	NSMAX	=	1000,
	NSLOG	=	7,
	NSCACHE	=	(1<<NSLOG)
};

struct Mntwalk				/* state for /proc/#/ns */
{
	int	cddone;
	ulong	id;
	Mhead*	mh;
	Mount*	cm;
};

struct Mount
{
	ulong	mountid;
	Mount*	next;
	Mhead*	head;
	Mount*	copy;
	Mount*	order;
	Chan*	to;			/* channel replacing channel */
	int	mflag;
	char	*spec;
};

struct Mhead
{
	Ref		r;
	RWLock	lock;
	Chan*	from;			/* channel mounted upon */
	Mount*	mount;			/* what's mounted upon it */
	Mhead*	hash;			/* Hash chain */
};

struct Mnt
{
	Lock	l;
	/* references are counted using c->ref; channels on this mount point incref(c->mchan) == Mnt.c */
	Chan*	c;		/* Channel to file service */
	Proc	*rip;		/* Reader in progress */
	Mntrpc*	queue;		/* Queue of pending requests on this channel */
	ulong	id;		/* Multiplexor id for channel check */
	Mnt*	list;		/* Free list */
	int	flags;		/* cache */
	int	msize;		/* data + IOHDRSZ */
	char	*version;	/* 9P version */
	Queue	*q;		/* input queue */
};

enum
{
	MNTLOG	=	5,
	MNTHASH =	1<<MNTLOG,		/* Hash to walk mount table */
	INITNFD =	100,		/* init per process file descriptors */
	MAXNFD =	4096,		/* max per process file descriptors */
};
#define MOUNTH(p,qid)	((p)->mnthash[(qid).path&((1<<MNTLOG)-1)])

struct Nsconf
{
	int	flags;
	int	stacksize;		/* per thread */
	char	*rootdir;
	char	*name;
	char	*Name;
	char	*consname;
	char	*eve;

	void (*addproc)(Proc*);
	void	(*fault)(char*);
};

enum
{
	NsGraphics = (1<<0),
	NsCmap7 = (1<<1),
	NsNoperm = (1<<2)		/* don't check permissions in devfs */
};

struct Pgrp
{
	Ref	r;			/* also used as a lock when mounting */
	int	noattach;
	ulong	pgrpid;
	RWLock	ns;			/* Namespace n read/one write lock */
	QLock	nsh;
	Mhead*	mnthash[MNTHASH];
	int	progmode;
	Chan*	dot;
	Chan*	slash;
};

struct Fgrp
{
	Ref	r;
	Chan**	fd;
	int	nfd;			/* number of fd slots */
	int	maxfd;			/* highest fd in use */
	int	minfd;			/* lower bound on free fd */
};

struct Pointer
{
	int	x;
	int	y;
	int	b;
	int	modify;
	Rendez	r;
};

struct Osenv
{
	char	error[ERRMAX];	/* Last system error */
	Pgrp*	pgrp;		/* Ref to namespace, working dir and root */
	Fgrp*	fgrp;		/* Ref to file descriptors */
	Rendez*	rend;		/* Synchro point */
	Queue*	waitq;		/* Info about dead children */
	Queue*	childq;		/* Info about children for debuggers */
	void*	debug;		/* Debugging master */
	char	*user;	/* Inferno user name */
	FPU	fpu;		/* Floating point thread state */
	int	uid;		/* Numeric user id for host system */
	int	gid;		/* Numeric group id for host system */
	void	*ui;		/* User info for NT */
};

enum
{
	Unknown = 0xdeadbabe,
	IdleGC	= 0x16,
	Interp	= 0x17
};

struct	Proc
{
	int	type;		/* interpreter or not */
	char	*text;
	Proc*	qnext;		/* list of processes waiting on a Qlock */
	int	pid;
	Proc*	next;		/* list of created processes */
	Proc*	prev;
	Rendez*	r;		/* rendezvous we are Sleeping on */
	Rendez	sleep;		/* place to sleep */
	int	swipend;	/* software interrupt pending for Prog */
	int	syscall;	/* set true under sysio for interruptable syscalls */
	int	killed;		/* software interrupt of Proc */
	int	intwait;	/* spin wait for note to turn up */
	Tid	sigid;		/* handle used for signal/note/exception */
	Lock	sysio;		/* note handler lock */
	int	nerr;		/* error stack SP */
	char*	kstack;
	jmp_buf	estack[32];	/* vector of error jump labels */
	void	(*func)(void*);	/* saved trampoline pointer for kproc */
	void*	arg;		/* arg for invoked kproc function */
	void*	iprog;		/* work for Prog after release */
	void*	prog;		/* fake prog for slaves eg. exportfs */
	Osenv*	env;		/* effective operating system environment */
	Osenv	defenv;		/* default env for slaves with no prog */
	char	genbuf[128];	/* buffer used e.g. for last name element from namec */
	jmp_buf	privstack;	/* private stack for making new kids */
	jmp_buf	sharestack;
	Proc	*kid;
	void	*kidsp;
};

#define poperror()	up->nerr--
#define	waserror()	(up->nerr++, setjmp(up->estack[up->nerr-1]))

struct Procs
{
	Lock	l;
	Proc*	head;
	Proc*	tail;
};

struct Rb
{
	QLock	l;
	Rendez	producer;
	Rendez	consumer;
	Rendez	clock;
	ulong	randomcount;
	uchar	buf[4096];
	uchar	*ep;
	uchar	*rp;
	uchar	*wp;
	uchar	next;
	uchar	bits;
	uchar	wakeme;
	uchar	filled;
	int	target;
	int	kprocstarted;
};

extern	Dev*	devtab[];
extern	char	*ossysname;
extern	char	*eve;
extern	int cpuserver;
extern	Nsconf nsconf;

extern	Block*	allocb(int);
extern	Block*	bl2mem(uchar*, Block*, int);
extern	int	blocklen(Block*);
extern	void	cclose(Chan*);
extern	void	chandevinit(void);
extern	void	chandevreset(void);
extern	void	chanfree(Chan*);
extern	void	clearintr(void);
extern	Chan*	cclone(Chan*);
extern	void	closepgrp(Pgrp*);
extern	void	closefgrp(Fgrp*);
extern	int	cmount(Chan* volatile*, Chan*, int, char*);
extern	void	cunmount(Chan*, Chan*);
extern	int	decref(Ref*);
extern	int	decrypt(void*, void*, int);
extern	void	drawflush(void);
extern	Fgrp*	dupfgrp(Fgrp*);
extern	int	encrypt(void*, void*, int);
extern	int	eqqid(Qid, Qid);
extern	int	export(int, int);
extern	Chan*	fdtochan(Fgrp*, int, int, int, int);
extern	void	freeb(Block*);
extern	void	freeblist(Block*);
extern	long	hostownerwrite(char*, int);
extern	int	incref(Ref*);
extern	int	iprint(char*, ...);
extern	void	isdir(Chan*);
extern	int	iseve(void);
extern  long	keyread(char*, int, long);
extern  long	keywrite(char*, int);
extern	void	kbdinit(void);
extern	void	kbdputc(int);
extern	Block*	mem2bl(uchar*, int);
extern	void	mkqid(Qid*, vlong, ulong, int);
extern	int	nsaddproc(char*, void (*)(void*), void*, int);
extern	long	latin1(Rune*, int);
extern	void	mountfree(Mount*);
extern	Chan*	namec(char*, int, int, ulong);
extern	void	nameok(char*);
extern	Chan*	newchan(void);
extern	Fgrp*	newfgrp(Fgrp*);
extern	Mount*	newmount(Mhead*, Chan*, int, char*);
extern	Pgrp*	newpgrp(void);
extern	char*	nextelem(char*, char*);
extern	void	nexterror(void);
Cname*		newcname(char*);
extern	int	nrand(int n);
extern	void	nsinit(void);
extern  int	openmode(ulong);
extern	void	osenter(void);
extern	void	oserror(void);
extern	void	osleave(void);
extern	void	osfillproc(Proc*);
extern	Block*	padblock(Block*, int);
extern	void	panic(char*, ...);
extern	void	pexit(char*, int);
extern	void	procserve(void);
extern	int	pullblock(Block**, int);
extern	Block*	pullupblock(Block*, int);
extern	Block*	pullupqueue(Queue*, int);
extern	void	putmhead(Mhead*);
extern	void	qadd(Queue*, Block*);
extern	void	qaddlist(Queue*, Block*);
extern	Block*	qbread(Queue*, int);
extern	long	qbwrite(Queue*, Block*);
extern	int	qcanread(Queue*);
extern	void	qclose(Queue*);
extern	int	qconsume(Queue*, void*, int);
extern	int	qdiscard(Queue*, int);
extern	void	qflush(Queue*);
extern	void	qfree(Queue*);
extern	void	qhangup(Queue*, char*);
extern	void	qinit(void);
extern	int	qlen(Queue*);
extern	Queue*	qopen(int, int, void (*)(void*), void*);
extern	int	qpass(Queue*, Block*);
extern	int	qproduce(Queue*, void*, int);
extern	void	qputback(Queue*, Block*);
extern	long	qread(Queue*, void*, int);
extern	Block*	qremove(Queue*);
extern	void	qreopen(Queue*);
extern	int	qwindow(Queue*);
extern	int	qiwrite(Queue*, void*, int);
extern	int	qwrite(Queue*, void*, int);
extern	void	qsetlimit(Queue*, int);
extern	void	qnoblock(Queue*, int);
extern	int	readkbd(void);
extern	int	readstr(ulong, char*, ulong, char*);
extern  int	running(void);
extern	void	(*screenputs)(char*, int);
extern	char*	skipslash(char*);
extern	void*	smalloc(ulong);
extern  int	ticks(void);
extern	long	unionread(Chan*, void*, long);
extern	void	validname(char*, int);

/* generic device functions */
extern	void	devinit(void);
extern  void	devreset(void);
extern	Chan*	devattach(int, char*);
extern	Chan*	devattach(int, char*);
extern	Block*	devbread(Chan*, long, ulong);
extern	long	devbwrite(Chan*, Block*, ulong);
extern	void	devcreate(Chan*, char*, int, ulong);
extern  void	devdir(Chan*, Qid, char*, vlong, char*, long, Dir*);
extern  long	devdirread(Chan*, char*, long, Dirtab*, int, Devgen*);
extern	Chan*	devclone(Chan*);
Devgen		devgen;
extern	int	devno(int, int);
extern	Chan*	devopen(Chan*, int, Dirtab*, int, Devgen*);
extern	void		devpermcheck(char*, ulong, int);
extern	int	devstat(Chan*, uchar*, int, Dirtab*, int, Devgen*);
extern	Walkqid*	devwalk(Chan*, Chan*, char**, int, Dirtab*, int, Devgen*);
extern	void	devremove(Chan*);
extern	int	devwstat(Chan*, uchar*, int);

#define DEVDOTDOT	-1
