xref: /plan9/sys/src/cmd/aux/consolefs.c (revision 8498559bac70ac8118e6f36ad9d674181f43f45d)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <auth.h>
47dd7cddfSDavid du Colombier #include <fcall.h>
57dd7cddfSDavid du Colombier #include <bio.h>
67dd7cddfSDavid du Colombier #include <ndb.h>
77dd7cddfSDavid du Colombier #include <thread.h>
87dd7cddfSDavid du Colombier 
97dd7cddfSDavid du Colombier /*
107dd7cddfSDavid du Colombier  *  This fs presents a 1 level file system.  It contains
118bc54264SDavid du Colombier  *  up to three files per console (xxx and xxxctl and xxxstat)
127dd7cddfSDavid du Colombier  */
137dd7cddfSDavid du Colombier 
147dd7cddfSDavid du Colombier typedef struct Console Console;
157dd7cddfSDavid du Colombier typedef struct Fid Fid;
167dd7cddfSDavid du Colombier typedef struct Request Request;
177dd7cddfSDavid du Colombier typedef struct Reqlist Reqlist;
187dd7cddfSDavid du Colombier typedef struct Fs Fs;
197dd7cddfSDavid du Colombier 
207dd7cddfSDavid du Colombier enum
217dd7cddfSDavid du Colombier {
227dd7cddfSDavid du Colombier 	/* last 5 bits of qid.path */
237dd7cddfSDavid du Colombier 	Textern=	0,		/* fake parent of top level */
247dd7cddfSDavid du Colombier 	Ttopdir,			/* top level directory */
257dd7cddfSDavid du Colombier 	Qctl,
267dd7cddfSDavid du Colombier 	Qstat,
277dd7cddfSDavid du Colombier 	Qdata,
287dd7cddfSDavid du Colombier 
297dd7cddfSDavid du Colombier 	Bufsize=	32*1024,	/* chars buffered per reader */
307dd7cddfSDavid du Colombier 	Maxcons=	64,		/* maximum consoles */
317dd7cddfSDavid du Colombier 	Nhash=		64,		/* Fid hash buckets */
327dd7cddfSDavid du Colombier };
337dd7cddfSDavid du Colombier 
349a747e4fSDavid du Colombier #define TYPE(x)		(((ulong)x.path) & 0xf)
359a747e4fSDavid du Colombier #define CONS(x)		((((ulong)x.path) >> 4)&0xfff)
367dd7cddfSDavid du Colombier #define QID(c, x)	(((c)<<4) | (x))
377dd7cddfSDavid du Colombier 
387dd7cddfSDavid du Colombier struct Request
397dd7cddfSDavid du Colombier {
407dd7cddfSDavid du Colombier 	Request	*next;
417dd7cddfSDavid du Colombier 	Fid	*fid;
427dd7cddfSDavid du Colombier 	Fs	*fs;
437dd7cddfSDavid du Colombier 	Fcall	f;
449a747e4fSDavid du Colombier 	uchar	buf[1];
457dd7cddfSDavid du Colombier };
467dd7cddfSDavid du Colombier 
477dd7cddfSDavid du Colombier struct Reqlist
487dd7cddfSDavid du Colombier {
497dd7cddfSDavid du Colombier 	Lock;
507dd7cddfSDavid du Colombier 	Request	*first;
517dd7cddfSDavid du Colombier 	Request *last;
527dd7cddfSDavid du Colombier };
537dd7cddfSDavid du Colombier 
547dd7cddfSDavid du Colombier struct Fid
557dd7cddfSDavid du Colombier {
567dd7cddfSDavid du Colombier 	Lock;
577dd7cddfSDavid du Colombier 	Fid	*next;			/* hash list */
587dd7cddfSDavid du Colombier 	Fid	*cnext;			/* list of Fid's on a console */
597dd7cddfSDavid du Colombier 	int	fid;
607dd7cddfSDavid du Colombier 	int	ref;
617dd7cddfSDavid du Colombier 
627dd7cddfSDavid du Colombier 	int	attached;
637dd7cddfSDavid du Colombier 	int	open;
649a747e4fSDavid du Colombier 	char	*user;
658bc54264SDavid du Colombier 	char	mbuf[Bufsize];		/* message */
668bc54264SDavid du Colombier 	int	bufn;
678bc54264SDavid du Colombier 	int	used;
687dd7cddfSDavid du Colombier 	Qid	qid;
697dd7cddfSDavid du Colombier 
707dd7cddfSDavid du Colombier 	Console	*c;
717dd7cddfSDavid du Colombier 
727dd7cddfSDavid du Colombier 	char	buf[Bufsize];
737dd7cddfSDavid du Colombier 	char	*rp;
747dd7cddfSDavid du Colombier 	char	*wp;
757dd7cddfSDavid du Colombier 
767dd7cddfSDavid du Colombier 	Reqlist	r;			/* active read requests */
777dd7cddfSDavid du Colombier };
787dd7cddfSDavid du Colombier 
797dd7cddfSDavid du Colombier struct Console
807dd7cddfSDavid du Colombier {
817dd7cddfSDavid du Colombier 	Lock;
827dd7cddfSDavid du Colombier 
837dd7cddfSDavid du Colombier 	char	*name;
847dd7cddfSDavid du Colombier 	char	*dev;
857dd7cddfSDavid du Colombier 	int	speed;
867dd7cddfSDavid du Colombier 	int	cronly;
877dd7cddfSDavid du Colombier 	int	ondemand;		/* open only on demand */
888bc54264SDavid du Colombier 	int	chat;			/* chat consoles are special */
897dd7cddfSDavid du Colombier 
907dd7cddfSDavid du Colombier 	int	pid;			/* pid of reader */
917dd7cddfSDavid du Colombier 
927dd7cddfSDavid du Colombier 	int	fd;
937dd7cddfSDavid du Colombier 	int	cfd;
947dd7cddfSDavid du Colombier 	int	sfd;
957dd7cddfSDavid du Colombier 
967dd7cddfSDavid du Colombier 	Fid	*flist;			/* open fids to broadcast to */
977dd7cddfSDavid du Colombier };
987dd7cddfSDavid du Colombier 
997dd7cddfSDavid du Colombier struct Fs
1007dd7cddfSDavid du Colombier {
1017dd7cddfSDavid du Colombier 	Lock;
1027dd7cddfSDavid du Colombier 
1037dd7cddfSDavid du Colombier 	int	fd;			/* to kernel mount point */
1049a747e4fSDavid du Colombier 	int	messagesize;
1057dd7cddfSDavid du Colombier 	Fid	*hash[Nhash];
1067dd7cddfSDavid du Colombier 	Console	*cons[Maxcons];
1077dd7cddfSDavid du Colombier 	int	ncons;
1087dd7cddfSDavid du Colombier };
1097dd7cddfSDavid du Colombier 
1107dd7cddfSDavid du Colombier extern	void	console(Fs*, char*, char*, int, int, int);
1117dd7cddfSDavid du Colombier extern	Fs*	fsmount(char*);
1127dd7cddfSDavid du Colombier 
1137dd7cddfSDavid du Colombier extern	void	fsreader(void*);
1147dd7cddfSDavid du Colombier extern	void	fsrun(void*);
1157dd7cddfSDavid du Colombier extern	Fid*	fsgetfid(Fs*, int);
1167dd7cddfSDavid du Colombier extern	void	fsputfid(Fs*, Fid*);
1179a747e4fSDavid du Colombier extern	int	fsdirgen(Fs*, Qid, int, Dir*, uchar*, int);
1187dd7cddfSDavid du Colombier extern	void	fsreply(Fs*, Request*, char*);
1197dd7cddfSDavid du Colombier extern	void	fskick(Fs*, Fid*);
1207dd7cddfSDavid du Colombier extern	int	fsreopen(Fs*, Console*);
1217dd7cddfSDavid du Colombier 
1229a747e4fSDavid du Colombier extern	void	fsversion(Fs*, Request*, Fid*);
1237dd7cddfSDavid du Colombier extern	void	fsflush(Fs*, Request*, Fid*);
1249a747e4fSDavid du Colombier extern	void	fsauth(Fs*, Request*, Fid*);
1257dd7cddfSDavid du Colombier extern	void	fsattach(Fs*, Request*, Fid*);
1267dd7cddfSDavid du Colombier extern	void	fswalk(Fs*, Request*, Fid*);
1277dd7cddfSDavid du Colombier extern	void	fsclwalk(Fs*, Request*, Fid*);
1287dd7cddfSDavid du Colombier extern	void	fsopen(Fs*, Request*, Fid*);
1297dd7cddfSDavid du Colombier extern	void	fscreate(Fs*, Request*, Fid*);
1307dd7cddfSDavid du Colombier extern	void	fsread(Fs*, Request*, Fid*);
1317dd7cddfSDavid du Colombier extern	void	fswrite(Fs*, Request*, Fid*);
1327dd7cddfSDavid du Colombier extern	void	fsclunk(Fs*, Request*, Fid*);
1337dd7cddfSDavid du Colombier extern	void	fsremove(Fs*, Request*, Fid*);
1347dd7cddfSDavid du Colombier extern	void	fsstat(Fs*, Request*, Fid*);
1357dd7cddfSDavid du Colombier extern	void	fswstat(Fs*, Request*, Fid*);
1367dd7cddfSDavid du Colombier 
1377dd7cddfSDavid du Colombier 
1387dd7cddfSDavid du Colombier void 	(*fcall[])(Fs*, Request*, Fid*) =
1397dd7cddfSDavid du Colombier {
1407dd7cddfSDavid du Colombier 	[Tflush]	fsflush,
1419a747e4fSDavid du Colombier 	[Tversion]	fsversion,
1429a747e4fSDavid du Colombier 	[Tauth]	fsauth,
1437dd7cddfSDavid du Colombier 	[Tattach]	fsattach,
1447dd7cddfSDavid du Colombier 	[Twalk]		fswalk,
1457dd7cddfSDavid du Colombier 	[Topen]		fsopen,
1467dd7cddfSDavid du Colombier 	[Tcreate]	fscreate,
1477dd7cddfSDavid du Colombier 	[Tread]		fsread,
1487dd7cddfSDavid du Colombier 	[Twrite]	fswrite,
1497dd7cddfSDavid du Colombier 	[Tclunk]	fsclunk,
1507dd7cddfSDavid du Colombier 	[Tremove]	fsremove,
1517dd7cddfSDavid du Colombier 	[Tstat]		fsstat,
1527dd7cddfSDavid du Colombier 	[Twstat]	fswstat
1537dd7cddfSDavid du Colombier };
1547dd7cddfSDavid du Colombier 
1557dd7cddfSDavid du Colombier char Eperm[] = "permission denied";
1567dd7cddfSDavid du Colombier char Eexist[] = "file does not exist";
1577dd7cddfSDavid du Colombier char Enotdir[] = "not a directory";
1587dd7cddfSDavid du Colombier char Eisopen[] = "file already open";
1597dd7cddfSDavid du Colombier char Ebadcount[] = "bad read/write count";
1607dd7cddfSDavid du Colombier char Enofid[] = "no such fid";
1617dd7cddfSDavid du Colombier 
1627dd7cddfSDavid du Colombier char *consoledb = "/lib/ndb/consoledb";
1637dd7cddfSDavid du Colombier char *mntpt = "/mnt/consoles";
1647dd7cddfSDavid du Colombier 
1659a747e4fSDavid du Colombier int messagesize = 8192+IOHDRSZ;
1669a747e4fSDavid du Colombier 
1677dd7cddfSDavid du Colombier void
fatal(char * fmt,...)1687dd7cddfSDavid du Colombier fatal(char *fmt, ...)
1697dd7cddfSDavid du Colombier {
1707dd7cddfSDavid du Colombier 	va_list arg;
1717dd7cddfSDavid du Colombier 	char buf[1024];
1727dd7cddfSDavid du Colombier 
1737dd7cddfSDavid du Colombier 	write(2, "consolefs: ", 10);
1747dd7cddfSDavid du Colombier 	va_start(arg, fmt);
1759a747e4fSDavid du Colombier 	vseprint(buf, buf+1024, fmt, arg);
1767dd7cddfSDavid du Colombier 	va_end(arg);
1777dd7cddfSDavid du Colombier 	write(2, buf, strlen(buf));
1787dd7cddfSDavid du Colombier 	write(2, "\n", 1);
1797dd7cddfSDavid du Colombier 	threadexitsall(fmt);
1807dd7cddfSDavid du Colombier }
1817dd7cddfSDavid du Colombier 
1827dd7cddfSDavid du Colombier 
1837dd7cddfSDavid du Colombier void*
emalloc(uint n)1847dd7cddfSDavid du Colombier emalloc(uint n)
1857dd7cddfSDavid du Colombier {
1867dd7cddfSDavid du Colombier 	void *p;
1877dd7cddfSDavid du Colombier 
1887dd7cddfSDavid du Colombier 	p = malloc(n);
1897dd7cddfSDavid du Colombier 	if(p == nil)
1907dd7cddfSDavid du Colombier 		fatal("malloc failed: %r");
1917dd7cddfSDavid du Colombier 	memset(p, 0, n);
1927dd7cddfSDavid du Colombier 	return p;
1937dd7cddfSDavid du Colombier }
1947dd7cddfSDavid du Colombier 
1957dd7cddfSDavid du Colombier int debug;
1967dd7cddfSDavid du Colombier Ndb *db;
1977dd7cddfSDavid du Colombier 
1987dd7cddfSDavid du Colombier /*
1997dd7cddfSDavid du Colombier  *  any request that can get queued for a delayed reply
2007dd7cddfSDavid du Colombier  */
2017dd7cddfSDavid du Colombier Request*
allocreq(Fs * fs,int bufsize)2027dd7cddfSDavid du Colombier allocreq(Fs *fs, int bufsize)
2037dd7cddfSDavid du Colombier {
2047dd7cddfSDavid du Colombier 	Request *r;
2057dd7cddfSDavid du Colombier 
2067dd7cddfSDavid du Colombier 	r = emalloc(sizeof(Request)+bufsize);
2077dd7cddfSDavid du Colombier 	r->fs = fs;
2087dd7cddfSDavid du Colombier 	r->next = nil;
2097dd7cddfSDavid du Colombier 	return r;
2107dd7cddfSDavid du Colombier }
2117dd7cddfSDavid du Colombier 
2127dd7cddfSDavid du Colombier /*
2137dd7cddfSDavid du Colombier  *  for maintaining lists of requests
2147dd7cddfSDavid du Colombier  */
2157dd7cddfSDavid du Colombier void
addreq(Reqlist * l,Request * r)2167dd7cddfSDavid du Colombier addreq(Reqlist *l, Request *r)
2177dd7cddfSDavid du Colombier {
2187dd7cddfSDavid du Colombier 	lock(l);
2197dd7cddfSDavid du Colombier 	if(l->first == nil)
2207dd7cddfSDavid du Colombier 		l->first = r;
2217dd7cddfSDavid du Colombier 	else
2227dd7cddfSDavid du Colombier 		l->last->next = r;
2237dd7cddfSDavid du Colombier 	l->last = r;
2247dd7cddfSDavid du Colombier 	r->next = nil;
2257dd7cddfSDavid du Colombier 	unlock(l);
2267dd7cddfSDavid du Colombier }
2277dd7cddfSDavid du Colombier 
2287dd7cddfSDavid du Colombier /*
2297dd7cddfSDavid du Colombier  *  remove the first request from a list of requests
2307dd7cddfSDavid du Colombier  */
2317dd7cddfSDavid du Colombier Request*
remreq(Reqlist * l)2327dd7cddfSDavid du Colombier remreq(Reqlist *l)
2337dd7cddfSDavid du Colombier {
2347dd7cddfSDavid du Colombier 	Request *r;
2357dd7cddfSDavid du Colombier 
2367dd7cddfSDavid du Colombier 	lock(l);
2377dd7cddfSDavid du Colombier 	r = l->first;
2387dd7cddfSDavid du Colombier 	if(r != nil)
2397dd7cddfSDavid du Colombier 		l->first = r->next;
2407dd7cddfSDavid du Colombier 	unlock(l);
2417dd7cddfSDavid du Colombier 	return r;
2427dd7cddfSDavid du Colombier }
2437dd7cddfSDavid du Colombier 
2447dd7cddfSDavid du Colombier /*
2457dd7cddfSDavid du Colombier  *  remove a request with the given tag from a list of requests
2467dd7cddfSDavid du Colombier  */
2477dd7cddfSDavid du Colombier Request*
remtag(Reqlist * l,int tag)2487dd7cddfSDavid du Colombier remtag(Reqlist *l, int tag)
2497dd7cddfSDavid du Colombier {
2507dd7cddfSDavid du Colombier 	Request *or, **ll;
2517dd7cddfSDavid du Colombier 
2527dd7cddfSDavid du Colombier 	lock(l);
2537dd7cddfSDavid du Colombier 	ll = &l->first;
2547dd7cddfSDavid du Colombier 	for(or = *ll; or; or = or->next){
2557dd7cddfSDavid du Colombier 		if(or->f.tag == tag){
2567dd7cddfSDavid du Colombier 			*ll = or->next;
2577dd7cddfSDavid du Colombier 			unlock(l);
2587dd7cddfSDavid du Colombier 			return or;
2597dd7cddfSDavid du Colombier 		}
2607dd7cddfSDavid du Colombier 		ll = &or->next;
2617dd7cddfSDavid du Colombier 	}
2627dd7cddfSDavid du Colombier 	unlock(l);
2637dd7cddfSDavid du Colombier 	return nil;
2647dd7cddfSDavid du Colombier }
2657dd7cddfSDavid du Colombier 
2667dd7cddfSDavid du Colombier Qid
parentqid(Qid q)2677dd7cddfSDavid du Colombier parentqid(Qid q)
2687dd7cddfSDavid du Colombier {
2699a747e4fSDavid du Colombier 	if(q.type & QTDIR)
2709a747e4fSDavid du Colombier 		return (Qid){QID(0, Textern), 0, QTDIR};
2717dd7cddfSDavid du Colombier 	else
2729a747e4fSDavid du Colombier 		return (Qid){QID(0, Ttopdir), 0, QTDIR};
2737dd7cddfSDavid du Colombier }
2747dd7cddfSDavid du Colombier 
2757dd7cddfSDavid du Colombier int
fsdirgen(Fs * fs,Qid parent,int i,Dir * d,uchar * buf,int nbuf)2769a747e4fSDavid du Colombier fsdirgen(Fs *fs, Qid parent, int i, Dir *d, uchar *buf, int nbuf)
2777dd7cddfSDavid du Colombier {
2789a747e4fSDavid du Colombier 	static char name[64];
2797dd7cddfSDavid du Colombier 	char *p;
2807dd7cddfSDavid du Colombier 	int xcons;
2817dd7cddfSDavid du Colombier 
2829a747e4fSDavid du Colombier 	d->uid = d->gid = d->muid = "network";
2837dd7cddfSDavid du Colombier 	d->length = 0;
2847dd7cddfSDavid du Colombier 	d->atime = time(nil);
2857dd7cddfSDavid du Colombier 	d->mtime = d->atime;
2867dd7cddfSDavid du Colombier 	d->type = 'C';
2877dd7cddfSDavid du Colombier 	d->dev = '0';
2887dd7cddfSDavid du Colombier 
2897dd7cddfSDavid du Colombier 	switch(TYPE(parent)){
2907dd7cddfSDavid du Colombier 	case Textern:
2917dd7cddfSDavid du Colombier 		if(i != 0)
2927dd7cddfSDavid du Colombier 			return -1;
2937dd7cddfSDavid du Colombier 		p = "consoles";
2949a747e4fSDavid du Colombier 		d->mode = DMDIR|0555;
2959a747e4fSDavid du Colombier 		d->qid.type = QTDIR;
2969a747e4fSDavid du Colombier 		d->qid.path = QID(0, Ttopdir);
2979a747e4fSDavid du Colombier 		d->qid.vers = 0;
2987dd7cddfSDavid du Colombier 		break;
2997dd7cddfSDavid du Colombier 	case Ttopdir:
3007dd7cddfSDavid du Colombier 		xcons = i/3;
3017dd7cddfSDavid du Colombier 		if(xcons >= fs->ncons)
3027dd7cddfSDavid du Colombier 			return -1;
3037dd7cddfSDavid du Colombier 		p = fs->cons[xcons]->name;
3047dd7cddfSDavid du Colombier 		switch(i%3){
3057dd7cddfSDavid du Colombier 		case 0:
306cb3cefd4SDavid du Colombier 			if(fs->cons[xcons]->cfd < 0)
307cb3cefd4SDavid du Colombier 				return 0;
3089a747e4fSDavid du Colombier 			snprint(name, sizeof name, "%sctl", p);
3097dd7cddfSDavid du Colombier 			p = name;
3109a747e4fSDavid du Colombier 			d->qid.type = QTFILE;
3119a747e4fSDavid du Colombier 			d->qid.path = QID(xcons, Qctl);
3129a747e4fSDavid du Colombier 			d->qid.vers = 0;
3137dd7cddfSDavid du Colombier 			break;
3147dd7cddfSDavid du Colombier 		case 1:
315cb3cefd4SDavid du Colombier 			if(fs->cons[xcons]->sfd < 0)
316cb3cefd4SDavid du Colombier 				return 0;
3179a747e4fSDavid du Colombier 			snprint(name, sizeof name, "%sstat", p);
3187dd7cddfSDavid du Colombier 			p = name;
3199a747e4fSDavid du Colombier 			d->qid.type = QTFILE;
3209a747e4fSDavid du Colombier 			d->qid.path = QID(xcons, Qstat);
3219a747e4fSDavid du Colombier 			d->qid.vers = 0;
3227dd7cddfSDavid du Colombier 			break;
3237dd7cddfSDavid du Colombier 		case 2:
3249a747e4fSDavid du Colombier 			d->qid.type = QTFILE;
3259a747e4fSDavid du Colombier 			d->qid.path = QID(xcons, Qdata);
3269a747e4fSDavid du Colombier 			d->qid.vers = 0;
3277dd7cddfSDavid du Colombier 			break;
3287dd7cddfSDavid du Colombier 		}
3297dd7cddfSDavid du Colombier 		d->mode = 0666;
3307dd7cddfSDavid du Colombier 		break;
3317dd7cddfSDavid du Colombier 	default:
3327dd7cddfSDavid du Colombier 		return -1;
3337dd7cddfSDavid du Colombier 	}
3349a747e4fSDavid du Colombier 	d->name = p;
3357dd7cddfSDavid du Colombier 	if(buf != nil)
3369a747e4fSDavid du Colombier 		return convD2M(d, buf, nbuf);
337cb3cefd4SDavid du Colombier 	return 1;
3387dd7cddfSDavid du Colombier }
3397dd7cddfSDavid du Colombier 
3407dd7cddfSDavid du Colombier /*
3417dd7cddfSDavid du Colombier  *  mount the user interface and start a request processor
3427dd7cddfSDavid du Colombier  */
3437dd7cddfSDavid du Colombier Fs*
fsmount(char * mntpt)3447dd7cddfSDavid du Colombier fsmount(char *mntpt)
3457dd7cddfSDavid du Colombier {
3467dd7cddfSDavid du Colombier 	Fs *fs;
3477dd7cddfSDavid du Colombier 	int pfd[2], srv;
3489a747e4fSDavid du Colombier 	char buf[32];
3497dd7cddfSDavid du Colombier 	int n;
3507dd7cddfSDavid du Colombier 	static void *v[2];
3517dd7cddfSDavid du Colombier 
3527dd7cddfSDavid du Colombier 	fs = emalloc(sizeof(Fs));
3537dd7cddfSDavid du Colombier 
3547dd7cddfSDavid du Colombier 	if(pipe(pfd) < 0)
3557dd7cddfSDavid du Colombier 		fatal("opening pipe: %r");
3567dd7cddfSDavid du Colombier 
3577dd7cddfSDavid du Colombier 	/* start up the file system process */
3587dd7cddfSDavid du Colombier 	v[0] = fs;
3597dd7cddfSDavid du Colombier 	v[1] = pfd;
3607dd7cddfSDavid du Colombier 	proccreate(fsrun, v, 16*1024);
3617dd7cddfSDavid du Colombier 
3627dd7cddfSDavid du Colombier 	/* Typically mounted before /srv exists */
3639a747e4fSDavid du Colombier 	if(access("#s/consoles", AEXIST) < 0){
3647dd7cddfSDavid du Colombier 		srv = create("#s/consoles", OWRITE, 0666);
3657dd7cddfSDavid du Colombier 		if(srv < 0)
3667dd7cddfSDavid du Colombier 			fatal("post: %r");
3677dd7cddfSDavid du Colombier 
3687dd7cddfSDavid du Colombier 		n = sprint(buf, "%d", pfd[1]);
3697dd7cddfSDavid du Colombier 		if(write(srv, buf, n) < 0)
3707dd7cddfSDavid du Colombier 			fatal("write srv: %r");
3717dd7cddfSDavid du Colombier 
3727dd7cddfSDavid du Colombier 		close(srv);
3737dd7cddfSDavid du Colombier 	}
3747dd7cddfSDavid du Colombier 
3759a747e4fSDavid du Colombier 	mount(pfd[1], -1, mntpt, MBEFORE, "");
3767dd7cddfSDavid du Colombier 	close(pfd[1]);
3777dd7cddfSDavid du Colombier 	return fs;
3787dd7cddfSDavid du Colombier }
3797dd7cddfSDavid du Colombier 
3807dd7cddfSDavid du Colombier /*
3817dd7cddfSDavid du Colombier  *  reopen a console
3827dd7cddfSDavid du Colombier  */
3837dd7cddfSDavid du Colombier int
fsreopen(Fs * fs,Console * c)3847dd7cddfSDavid du Colombier fsreopen(Fs* fs, Console *c)
3857dd7cddfSDavid du Colombier {
3867dd7cddfSDavid du Colombier 	char buf[128];
3877dd7cddfSDavid du Colombier 	static void *v[2];
3887dd7cddfSDavid du Colombier 
3897dd7cddfSDavid du Colombier 	if(c->pid){
3907dd7cddfSDavid du Colombier 		if(postnote(PNPROC, c->pid, "reopen") != 0)
3917dd7cddfSDavid du Colombier 			fprint(2, "postnote failed: %r\n");
3927dd7cddfSDavid du Colombier 		c->pid = 0;
3937dd7cddfSDavid du Colombier 	}
3947dd7cddfSDavid du Colombier 
3957dd7cddfSDavid du Colombier 	if(c->fd >= 0){
3967dd7cddfSDavid du Colombier 		close(c->fd);
3977dd7cddfSDavid du Colombier 		close(c->cfd);
3987dd7cddfSDavid du Colombier 		close(c->sfd);
3997dd7cddfSDavid du Colombier 		c->cfd = -1;
4007dd7cddfSDavid du Colombier 		c->fd = -1;
4017dd7cddfSDavid du Colombier 		c->sfd = -1;
4027dd7cddfSDavid du Colombier 	}
4037dd7cddfSDavid du Colombier 
4047dd7cddfSDavid du Colombier 	if(c->flist == nil && c->ondemand)
4057dd7cddfSDavid du Colombier 		return 0;
4067dd7cddfSDavid du Colombier 
4077dd7cddfSDavid du Colombier 	c->fd = open(c->dev, ORDWR);
4087dd7cddfSDavid du Colombier 	if(c->fd < 0)
4097dd7cddfSDavid du Colombier 		return -1;
4107dd7cddfSDavid du Colombier 
4117dd7cddfSDavid du Colombier 	snprint(buf, sizeof(buf), "%sctl", c->dev);
4127dd7cddfSDavid du Colombier 	c->cfd = open(buf, ORDWR);
4137dd7cddfSDavid du Colombier 	fprint(c->cfd, "b%d", c->speed);
4147dd7cddfSDavid du Colombier 
4157dd7cddfSDavid du Colombier 	snprint(buf, sizeof(buf), "%sstat", c->dev);
4167dd7cddfSDavid du Colombier 	c->sfd = open(buf, OREAD);
4177dd7cddfSDavid du Colombier 
4187dd7cddfSDavid du Colombier 	v[0] = fs;
4197dd7cddfSDavid du Colombier 	v[1] = c;
4207dd7cddfSDavid du Colombier 	proccreate(fsreader, v, 16*1024);
4217dd7cddfSDavid du Colombier 
4227dd7cddfSDavid du Colombier 	return 0;
4237dd7cddfSDavid du Colombier }
4247dd7cddfSDavid du Colombier 
4257dd7cddfSDavid du Colombier void
change(Fs * fs,Console * c,int doreopen,int speed,int cronly,int ondemand)4267dd7cddfSDavid du Colombier change(Fs *fs, Console *c, int doreopen, int speed, int cronly, int ondemand)
4277dd7cddfSDavid du Colombier {
4287dd7cddfSDavid du Colombier 	lock(c);
4297dd7cddfSDavid du Colombier 
4307dd7cddfSDavid du Colombier 	if(speed != c->speed){
4317dd7cddfSDavid du Colombier 		c->speed = speed;
4327dd7cddfSDavid du Colombier 		doreopen = 1;
4337dd7cddfSDavid du Colombier 	}
4347dd7cddfSDavid du Colombier 	if(ondemand != c->ondemand){
4357dd7cddfSDavid du Colombier 		c->ondemand = ondemand;
4367dd7cddfSDavid du Colombier 		doreopen = 1;
4377dd7cddfSDavid du Colombier 	}
4387dd7cddfSDavid du Colombier 	c->cronly = cronly;
4397dd7cddfSDavid du Colombier 	if(doreopen)
4407dd7cddfSDavid du Colombier 		fsreopen(fs, c);
4417dd7cddfSDavid du Colombier 
4427dd7cddfSDavid du Colombier 	unlock(c);
4437dd7cddfSDavid du Colombier }
4447dd7cddfSDavid du Colombier 
4457dd7cddfSDavid du Colombier /*
4467dd7cddfSDavid du Colombier  *  create a console interface
4477dd7cddfSDavid du Colombier  */
4487dd7cddfSDavid du Colombier void
console(Fs * fs,char * name,char * dev,int speed,int cronly,int ondemand)4497dd7cddfSDavid du Colombier console(Fs* fs, char *name, char *dev, int speed, int cronly, int ondemand)
4507dd7cddfSDavid du Colombier {
4517dd7cddfSDavid du Colombier 	Console *c;
4527dd7cddfSDavid du Colombier 	char *x;
4537dd7cddfSDavid du Colombier 	int i, doreopen;
4547dd7cddfSDavid du Colombier 
4557dd7cddfSDavid du Colombier 	if(fs->ncons >= Maxcons)
4567dd7cddfSDavid du Colombier 		fatal("too many consoles, too little time");
4577dd7cddfSDavid du Colombier 
4587dd7cddfSDavid du Colombier 	doreopen = 0;
4597dd7cddfSDavid du Colombier 	for(i = 0; i < fs->ncons; i++){
4607dd7cddfSDavid du Colombier 		c = fs->cons[i];
4617dd7cddfSDavid du Colombier 		if(strcmp(name, c->name) == 0){
4627dd7cddfSDavid du Colombier 			if(strcmp(dev, c->dev) != 0){
4637dd7cddfSDavid du Colombier 				/* new device */
4647dd7cddfSDavid du Colombier 				x = c->dev;
4657dd7cddfSDavid du Colombier 				c->dev = strdup(dev);
4667dd7cddfSDavid du Colombier 				free(x);
4677dd7cddfSDavid du Colombier 				doreopen = 1;
4687dd7cddfSDavid du Colombier 			}
4697dd7cddfSDavid du Colombier 			change(fs, c, doreopen, speed, cronly, ondemand);
4707dd7cddfSDavid du Colombier 			return;
4717dd7cddfSDavid du Colombier 		}
4727dd7cddfSDavid du Colombier 	}
47314cc0f53SDavid du Colombier #ifdef sapedoesntlikethis
47414cc0f53SDavid du Colombier 	/*
47514cc0f53SDavid du Colombier 	 * The code below prevents this from working.  I can't
47614cc0f53SDavid du Colombier 	 * think of scenarios where the code below actually helps
47714cc0f53SDavid du Colombier 	 *	Sape
47814cc0f53SDavid du Colombier 	 *
47914cc0f53SDavid du Colombier 	 * console=borneo dev=/dev/eia1
48014cc0f53SDavid du Colombier 	 * 	speed=9600
48114cc0f53SDavid du Colombier 	 * 	openondemand=1
48214cc0f53SDavid du Colombier 	 * console=tottie dev=/dev/eia1
48314cc0f53SDavid du Colombier 	 * 	speed=115200
48414cc0f53SDavid du Colombier 	 * 	openondemand=1
48514cc0f53SDavid du Colombier 	 */
4867dd7cddfSDavid du Colombier 	for(i = 0; i < fs->ncons; i++){
4877dd7cddfSDavid du Colombier 		c = fs->cons[i];
4887dd7cddfSDavid du Colombier 		if(strcmp(dev, c->dev) == 0){
4897dd7cddfSDavid du Colombier 			/* at least a rename */
4907dd7cddfSDavid du Colombier 			x = c->name;
4917dd7cddfSDavid du Colombier 			c->name = strdup(name);
4927dd7cddfSDavid du Colombier 			free(x);
4937dd7cddfSDavid du Colombier 			change(fs, c, doreopen, speed, cronly, ondemand);
4947dd7cddfSDavid du Colombier 			return;
4957dd7cddfSDavid du Colombier 		}
4967dd7cddfSDavid du Colombier 	}
49714cc0f53SDavid du Colombier #endif
4987dd7cddfSDavid du Colombier 	c = emalloc(sizeof(Console));
4997bd483b0SDavid du Colombier 	fs->cons[fs->ncons] = c;
5007bd483b0SDavid du Colombier 	fs->ncons++;
5017dd7cddfSDavid du Colombier 	c->name = strdup(name);
5027dd7cddfSDavid du Colombier 	c->dev = strdup(dev);
5038bc54264SDavid du Colombier 	if(strcmp(c->dev, "/dev/null") == 0)
5048bc54264SDavid du Colombier 		c->chat = 1;
5058bc54264SDavid du Colombier 	else
5068bc54264SDavid du Colombier 		c->chat = 0;
5077dd7cddfSDavid du Colombier 	c->fd = -1;
5087dd7cddfSDavid du Colombier 	c->cfd = -1;
5097dd7cddfSDavid du Colombier 	c->sfd = -1;
5107dd7cddfSDavid du Colombier 	change(fs, c, 1, speed, cronly, ondemand);
5117dd7cddfSDavid du Colombier }
5127dd7cddfSDavid du Colombier 
5137dd7cddfSDavid du Colombier /*
5147dd7cddfSDavid du Colombier  *  buffer data from console to a client.
5157dd7cddfSDavid du Colombier  *  circular q with writer able to catch up to reader.
5167dd7cddfSDavid du Colombier  *  the reader may miss data but always sees an in order sequence.
5177dd7cddfSDavid du Colombier  */
5187dd7cddfSDavid du Colombier void
fromconsole(Fid * f,char * p,int n)5197dd7cddfSDavid du Colombier fromconsole(Fid *f, char *p, int n)
5207dd7cddfSDavid du Colombier {
5217dd7cddfSDavid du Colombier 	char *rp, *wp, *ep;
5227dd7cddfSDavid du Colombier 	int pass;
5237dd7cddfSDavid du Colombier 
5247dd7cddfSDavid du Colombier 	lock(f);
5257dd7cddfSDavid du Colombier 	rp = f->rp;
5267dd7cddfSDavid du Colombier 	wp = f->wp;
5277dd7cddfSDavid du Colombier 	ep = f->buf + sizeof(f->buf);
5287dd7cddfSDavid du Colombier 	pass = 0;
5297dd7cddfSDavid du Colombier 	while(n--){
5307dd7cddfSDavid du Colombier 		*wp++ = *p++;
5317dd7cddfSDavid du Colombier 		if(wp >= ep)
5327dd7cddfSDavid du Colombier 			wp = f->buf;
5337dd7cddfSDavid du Colombier 		if(rp == wp)
5347dd7cddfSDavid du Colombier 			pass = 1;
5357dd7cddfSDavid du Colombier 	}
5367dd7cddfSDavid du Colombier 	f->wp = wp;
5377dd7cddfSDavid du Colombier 
5387dd7cddfSDavid du Colombier 	/*  we overtook the read pointer, push it up so readers always
5397dd7cddfSDavid du Colombier 	 *  see the tail of what was written
5407dd7cddfSDavid du Colombier 	 */
5417dd7cddfSDavid du Colombier 	if(pass){
5427dd7cddfSDavid du Colombier 		wp++;
5437dd7cddfSDavid du Colombier 		if(wp >= ep)
5447dd7cddfSDavid du Colombier 			f->rp = f->buf;
5457dd7cddfSDavid du Colombier 		else
5467dd7cddfSDavid du Colombier 			f->rp = wp;
5477dd7cddfSDavid du Colombier 	}
5487dd7cddfSDavid du Colombier 	unlock(f);
5497dd7cddfSDavid du Colombier }
5507dd7cddfSDavid du Colombier 
5517dd7cddfSDavid du Colombier /*
5527dd7cddfSDavid du Colombier  *  broadcast a list of members to all listeners
5537dd7cddfSDavid du Colombier  */
5547dd7cddfSDavid du Colombier void
bcastmembers(Fs * fs,Console * c,char * msg,Fid * f)5557dd7cddfSDavid du Colombier bcastmembers(Fs *fs, Console *c, char *msg, Fid *f)
5567dd7cddfSDavid du Colombier {
5577dd7cddfSDavid du Colombier 	int n;
5587dd7cddfSDavid du Colombier 	Fid *fl;
5597dd7cddfSDavid du Colombier 	char buf[512];
5607dd7cddfSDavid du Colombier 
5617dd7cddfSDavid du Colombier 	sprint(buf, "[%s%s", msg, f->user);
5629a747e4fSDavid du Colombier 	for(fl = c->flist; fl != nil && strlen(buf) + 64 < sizeof(buf); fl = fl->cnext){
5637dd7cddfSDavid du Colombier 		if(f == fl)
5647dd7cddfSDavid du Colombier 			continue;
5657dd7cddfSDavid du Colombier 		strcat(buf, ", ");
5667dd7cddfSDavid du Colombier 		strcat(buf, fl->user);
5677dd7cddfSDavid du Colombier 	}
5687dd7cddfSDavid du Colombier 	strcat(buf, "]\n");
5697dd7cddfSDavid du Colombier 
5707dd7cddfSDavid du Colombier 	n = strlen(buf);
5717dd7cddfSDavid du Colombier 	for(fl = c->flist; fl; fl = fl->cnext){
5727dd7cddfSDavid du Colombier 		fromconsole(fl, buf, n);
5737dd7cddfSDavid du Colombier 		fskick(fs, fl);
5747dd7cddfSDavid du Colombier 	}
5757dd7cddfSDavid du Colombier }
5767dd7cddfSDavid du Colombier 
5777dd7cddfSDavid du Colombier void
handler(void *,char * msg)5787dd7cddfSDavid du Colombier handler(void*, char *msg)
5797dd7cddfSDavid du Colombier {
5803b86f2f8SDavid du Colombier 	if(strstr(msg, "reopen") != nil ||
5813b86f2f8SDavid du Colombier 	   strstr(msg, "write on closed pipe") != nil)
5827dd7cddfSDavid du Colombier 		noted(NCONT);
5837dd7cddfSDavid du Colombier 	noted(NDFLT);
5847dd7cddfSDavid du Colombier }
5857dd7cddfSDavid du Colombier 
5867dd7cddfSDavid du Colombier /*
5877dd7cddfSDavid du Colombier  *  a process to read console output and broadcast it (one per console)
5887dd7cddfSDavid du Colombier  */
5897dd7cddfSDavid du Colombier void
fsreader(void * v)5907dd7cddfSDavid du Colombier fsreader(void *v)
5917dd7cddfSDavid du Colombier {
5927dd7cddfSDavid du Colombier 	int n;
5937dd7cddfSDavid du Colombier 	Fid *fl;
5947dd7cddfSDavid du Colombier 	char buf[1024];
5957dd7cddfSDavid du Colombier 	Fs *fs;
5967dd7cddfSDavid du Colombier 	Console *c;
5977dd7cddfSDavid du Colombier 	void **a;
5987dd7cddfSDavid du Colombier 
5997dd7cddfSDavid du Colombier 	a = v;
6007dd7cddfSDavid du Colombier 	fs = a[0];
6017dd7cddfSDavid du Colombier 	c = a[1];
6027dd7cddfSDavid du Colombier 	c->pid = getpid();
6037dd7cddfSDavid du Colombier 	notify(handler);
60465ae840eSDavid du Colombier 	if(c->chat)
60565ae840eSDavid du Colombier 		threadexits(nil);
6067dd7cddfSDavid du Colombier 	for(;;){
6077dd7cddfSDavid du Colombier 		n = read(c->fd, buf, sizeof(buf));
6087dd7cddfSDavid du Colombier 		if(n < 0)
6097dd7cddfSDavid du Colombier 			break;
6107dd7cddfSDavid du Colombier 		lock(c);
6117dd7cddfSDavid du Colombier 		for(fl = c->flist; fl; fl = fl->cnext){
6127dd7cddfSDavid du Colombier 			fromconsole(fl, buf, n);
6137dd7cddfSDavid du Colombier 			fskick(fs, fl);
6147dd7cddfSDavid du Colombier 		}
6157dd7cddfSDavid du Colombier 		unlock(c);
6167dd7cddfSDavid du Colombier 	}
6177dd7cddfSDavid du Colombier }
6187dd7cddfSDavid du Colombier 
6197dd7cddfSDavid du Colombier void
readdb(Fs * fs)6207dd7cddfSDavid du Colombier readdb(Fs *fs)
6217dd7cddfSDavid du Colombier {
6227dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt;
6237dd7cddfSDavid du Colombier 	char *dev, *cons;
6247dd7cddfSDavid du Colombier 	int cronly, speed, ondemand;
6257dd7cddfSDavid du Colombier 
6267dd7cddfSDavid du Colombier 	ndbreopen(db);
6277dd7cddfSDavid du Colombier 
6287dd7cddfSDavid du Colombier 	/* start a listener for each console */
6297dd7cddfSDavid du Colombier 	for(;;){
6307dd7cddfSDavid du Colombier 		t = ndbparse(db);
6317dd7cddfSDavid du Colombier 		if(t == nil)
6327dd7cddfSDavid du Colombier 			break;
6337dd7cddfSDavid du Colombier 		dev = nil;
6347dd7cddfSDavid du Colombier 		cons = nil;
6357dd7cddfSDavid du Colombier 		speed = 9600;
6367dd7cddfSDavid du Colombier 		cronly = 0;
6377dd7cddfSDavid du Colombier 		ondemand = 0;
6387dd7cddfSDavid du Colombier 		for(nt = t; nt; nt = nt->entry){
6397dd7cddfSDavid du Colombier 			if(strcmp(nt->attr, "console") == 0)
6407dd7cddfSDavid du Colombier 				cons = nt->val;
6417dd7cddfSDavid du Colombier 			else if(strcmp(nt->attr, "dev") == 0)
6427dd7cddfSDavid du Colombier 				dev = nt->val;
6437dd7cddfSDavid du Colombier 			else if(strcmp(nt->attr, "speed") == 0)
6447dd7cddfSDavid du Colombier 				speed = atoi(nt->val);
6457dd7cddfSDavid du Colombier 			else if(strcmp(nt->attr, "cronly") == 0)
6467dd7cddfSDavid du Colombier 				cronly = 1;
6477dd7cddfSDavid du Colombier 			else if(strcmp(nt->attr, "openondemand") == 0)
6487dd7cddfSDavid du Colombier 				ondemand = 1;
6497dd7cddfSDavid du Colombier 		}
6507dd7cddfSDavid du Colombier 		if(dev != nil && cons != nil)
6517dd7cddfSDavid du Colombier 			console(fs, cons, dev, speed, cronly, ondemand);
6527dd7cddfSDavid du Colombier 		ndbfree(t);
6537dd7cddfSDavid du Colombier 	}
6547dd7cddfSDavid du Colombier }
6557dd7cddfSDavid du Colombier 
6567dd7cddfSDavid du Colombier int dbmtime;
6577dd7cddfSDavid du Colombier 
6587dd7cddfSDavid du Colombier /*
6597dd7cddfSDavid du Colombier  *  a request processor (one per Fs)
6607dd7cddfSDavid du Colombier  */
6617dd7cddfSDavid du Colombier void
fsrun(void * v)6627dd7cddfSDavid du Colombier fsrun(void *v)
6637dd7cddfSDavid du Colombier {
6647dd7cddfSDavid du Colombier 	int n, t;
6657dd7cddfSDavid du Colombier 	Request *r;
6667dd7cddfSDavid du Colombier 	Fid *f;
6679a747e4fSDavid du Colombier 	Dir *d;
6687dd7cddfSDavid du Colombier 	void **a = v;
6697dd7cddfSDavid du Colombier 	Fs* fs;
6707dd7cddfSDavid du Colombier 	int *pfd;
6717dd7cddfSDavid du Colombier 
6727dd7cddfSDavid du Colombier 	fs = a[0];
6737dd7cddfSDavid du Colombier 	pfd = a[1];
6747dd7cddfSDavid du Colombier 	fs->fd = pfd[0];
6753b86f2f8SDavid du Colombier 	notify(handler);
6767dd7cddfSDavid du Colombier 	for(;;){
6779a747e4fSDavid du Colombier 		d = dirstat(consoledb);
6789a747e4fSDavid du Colombier 		if(d != nil && d->mtime != dbmtime){
6799a747e4fSDavid du Colombier 			dbmtime = d->mtime;
6807dd7cddfSDavid du Colombier 			readdb(fs);
6817dd7cddfSDavid du Colombier 		}
6829a747e4fSDavid du Colombier 		free(d);
6839a747e4fSDavid du Colombier 		r = allocreq(fs, messagesize);
6849a747e4fSDavid du Colombier 		n = read9pmsg(fs->fd, r->buf, messagesize);
6857dd7cddfSDavid du Colombier 		if(n <= 0)
6867dd7cddfSDavid du Colombier 			fatal("unmounted");
6877dd7cddfSDavid du Colombier 
6889a747e4fSDavid du Colombier 		if(convM2S(r->buf, n, &r->f) == 0){
6897dd7cddfSDavid du Colombier 			fprint(2, "can't convert %ux %ux %ux\n", r->buf[0],
6907dd7cddfSDavid du Colombier 				r->buf[1], r->buf[2]);
6917dd7cddfSDavid du Colombier 			free(r);
6927dd7cddfSDavid du Colombier 			continue;
6937dd7cddfSDavid du Colombier 		}
6947dd7cddfSDavid du Colombier 
6957dd7cddfSDavid du Colombier 
6967dd7cddfSDavid du Colombier 		f = fsgetfid(fs, r->f.fid);
6977dd7cddfSDavid du Colombier 		r->fid = f;
6987dd7cddfSDavid du Colombier 		if(debug)
6999a747e4fSDavid du Colombier 			fprint(2, "%F path %llux\n", &r->f, f->qid.path);
7007dd7cddfSDavid du Colombier 
7017dd7cddfSDavid du Colombier 		t = r->f.type;
7027dd7cddfSDavid du Colombier 		r->f.type++;
7037dd7cddfSDavid du Colombier 		(*fcall[t])(fs, r, f);
7047dd7cddfSDavid du Colombier 	}
7057dd7cddfSDavid du Colombier }
7067dd7cddfSDavid du Colombier 
7077dd7cddfSDavid du Colombier Fid*
fsgetfid(Fs * fs,int fid)7087dd7cddfSDavid du Colombier fsgetfid(Fs *fs, int fid)
7097dd7cddfSDavid du Colombier {
7107dd7cddfSDavid du Colombier 	Fid *f, *nf;
7117dd7cddfSDavid du Colombier 
7127dd7cddfSDavid du Colombier 	lock(fs);
7137dd7cddfSDavid du Colombier 	for(f = fs->hash[fid%Nhash]; f; f = f->next){
7147dd7cddfSDavid du Colombier 		if(f->fid == fid){
7157dd7cddfSDavid du Colombier 			f->ref++;
7167dd7cddfSDavid du Colombier 			unlock(fs);
7177dd7cddfSDavid du Colombier 			return f;
7187dd7cddfSDavid du Colombier 		}
7197dd7cddfSDavid du Colombier 	}
7207dd7cddfSDavid du Colombier 
7217dd7cddfSDavid du Colombier 	nf = emalloc(sizeof(Fid));
7227dd7cddfSDavid du Colombier 	nf->next = fs->hash[fid%Nhash];
7237dd7cddfSDavid du Colombier 	fs->hash[fid%Nhash] = nf;
7247dd7cddfSDavid du Colombier 	nf->fid = fid;
7257dd7cddfSDavid du Colombier 	nf->ref = 1;
7267dd7cddfSDavid du Colombier 	nf->wp = nf->buf;
7277dd7cddfSDavid du Colombier 	nf->rp = nf->wp;
7287dd7cddfSDavid du Colombier 	unlock(fs);
7297dd7cddfSDavid du Colombier 	return nf;
7307dd7cddfSDavid du Colombier }
7317dd7cddfSDavid du Colombier 
7327dd7cddfSDavid du Colombier void
fsputfid(Fs * fs,Fid * f)7337dd7cddfSDavid du Colombier fsputfid(Fs *fs, Fid *f)
7347dd7cddfSDavid du Colombier {
7357dd7cddfSDavid du Colombier 	Fid **l, *nf;
7367dd7cddfSDavid du Colombier 
7377dd7cddfSDavid du Colombier 	lock(fs);
7387dd7cddfSDavid du Colombier 	if(--f->ref > 0){
7397dd7cddfSDavid du Colombier 		unlock(fs);
7407dd7cddfSDavid du Colombier 		return;
7417dd7cddfSDavid du Colombier 	}
7427dd7cddfSDavid du Colombier 	for(l = &fs->hash[f->fid%Nhash]; nf = *l; l = &nf->next)
7437dd7cddfSDavid du Colombier 		if(nf == f){
7447dd7cddfSDavid du Colombier 			*l = f->next;
7457dd7cddfSDavid du Colombier 			break;
7467dd7cddfSDavid du Colombier 		}
7477dd7cddfSDavid du Colombier 	unlock(fs);
7489a747e4fSDavid du Colombier 	free(f->user);
7497dd7cddfSDavid du Colombier 	free(f);
7507dd7cddfSDavid du Colombier }
7517dd7cddfSDavid du Colombier 
7527dd7cddfSDavid du Colombier void
fsauth(Fs * fs,Request * r,Fid *)7539a747e4fSDavid du Colombier fsauth(Fs *fs, Request *r, Fid*)
7547dd7cddfSDavid du Colombier {
7559a747e4fSDavid du Colombier 	fsreply(fs, r, "consolefs: authentication not required");
7567dd7cddfSDavid du Colombier }
7577dd7cddfSDavid du Colombier 
7587dd7cddfSDavid du Colombier void
fsversion(Fs * fs,Request * r,Fid *)7599a747e4fSDavid du Colombier fsversion(Fs *fs, Request *r, Fid*)
7607dd7cddfSDavid du Colombier {
7619a747e4fSDavid du Colombier 
7629a747e4fSDavid du Colombier 	if(r->f.msize < 256){
7639a747e4fSDavid du Colombier 		fsreply(fs, r, "message size too small");
7649a747e4fSDavid du Colombier 		return;
7659a747e4fSDavid du Colombier 	}
7669a747e4fSDavid du Colombier 	messagesize = r->f.msize;
7679a747e4fSDavid du Colombier 	if(messagesize > 8192+IOHDRSZ)
7689a747e4fSDavid du Colombier 		messagesize = 8192+IOHDRSZ;
7699a747e4fSDavid du Colombier 	r->f.msize = messagesize;
7709a747e4fSDavid du Colombier 	if(strncmp(r->f.version, "9P2000", 6) != 0){
7719a747e4fSDavid du Colombier 		fsreply(fs, r, "unrecognized 9P version");
7729a747e4fSDavid du Colombier 		return;
7739a747e4fSDavid du Colombier 	}
7749a747e4fSDavid du Colombier 	r->f.version = "9P2000";
7757dd7cddfSDavid du Colombier 
7767dd7cddfSDavid du Colombier 	fsreply(fs, r, nil);
7777dd7cddfSDavid du Colombier }
7787dd7cddfSDavid du Colombier 
7797dd7cddfSDavid du Colombier void
fsflush(Fs * fs,Request * r,Fid * f)7807dd7cddfSDavid du Colombier fsflush(Fs *fs, Request *r, Fid *f)
7817dd7cddfSDavid du Colombier {
7827dd7cddfSDavid du Colombier 	Request *or;
7837dd7cddfSDavid du Colombier 
7847dd7cddfSDavid du Colombier 	or = remtag(&f->r, r->f.oldtag);
7857dd7cddfSDavid du Colombier 	if(or != nil){
7867dd7cddfSDavid du Colombier 		fsputfid(fs, or->fid);
7877dd7cddfSDavid du Colombier 		free(or);
7887dd7cddfSDavid du Colombier 	}
7897dd7cddfSDavid du Colombier 	fsreply(fs, r, nil);
7907dd7cddfSDavid du Colombier }
7917dd7cddfSDavid du Colombier 
7927dd7cddfSDavid du Colombier void
fsattach(Fs * fs,Request * r,Fid * f)7937dd7cddfSDavid du Colombier fsattach(Fs *fs, Request *r, Fid *f)
7947dd7cddfSDavid du Colombier {
7959a747e4fSDavid du Colombier 	f->qid.type = QTDIR;
7969a747e4fSDavid du Colombier 	f->qid.path = QID(0, Ttopdir);
7979a747e4fSDavid du Colombier 	f->qid.vers = 0;
7987dd7cddfSDavid du Colombier 
7997dd7cddfSDavid du Colombier 	if(r->f.uname[0])
8009a747e4fSDavid du Colombier 		f->user = strdup(r->f.uname);
8017dd7cddfSDavid du Colombier 	else
8029a747e4fSDavid du Colombier 		f->user = strdup("none");
8037dd7cddfSDavid du Colombier 
8047dd7cddfSDavid du Colombier 	/* hold down the fid till the clunk */
8057dd7cddfSDavid du Colombier 	f->attached = 1;
8067dd7cddfSDavid du Colombier 	lock(fs);
8077dd7cddfSDavid du Colombier 	f->ref++;
8087dd7cddfSDavid du Colombier 	unlock(fs);
8097dd7cddfSDavid du Colombier 
8107dd7cddfSDavid du Colombier 	r->f.qid = f->qid;
8117dd7cddfSDavid du Colombier 	fsreply(fs, r, nil);
8127dd7cddfSDavid du Colombier }
8137dd7cddfSDavid du Colombier 
8147dd7cddfSDavid du Colombier void
fswalk(Fs * fs,Request * r,Fid * f)8157dd7cddfSDavid du Colombier fswalk(Fs *fs, Request *r, Fid *f)
8167dd7cddfSDavid du Colombier {
8177dd7cddfSDavid du Colombier 	char *name;
8187dd7cddfSDavid du Colombier 	Dir d;
819cb3cefd4SDavid du Colombier 	int i, n, nqid, nwname;
8209a747e4fSDavid du Colombier 	Qid qid, wqid[MAXWELEM];
8219a747e4fSDavid du Colombier 	Fid *nf;
8229a747e4fSDavid du Colombier 	char *err;
8237dd7cddfSDavid du Colombier 
8247dd7cddfSDavid du Colombier 	if(f->attached == 0){
8257dd7cddfSDavid du Colombier 		fsreply(fs, r, Enofid);
8267dd7cddfSDavid du Colombier 		return;
8277dd7cddfSDavid du Colombier 	}
8287dd7cddfSDavid du Colombier 
8299a747e4fSDavid du Colombier 	nf = nil;
8309a747e4fSDavid du Colombier 	if(r->f.fid != r->f.newfid){
8319a747e4fSDavid du Colombier 		nf = fsgetfid(fs, r->f.newfid);
8329a747e4fSDavid du Colombier 		nf->attached = f->attached;
8339a747e4fSDavid du Colombier 		nf->open = f->open;
8349a747e4fSDavid du Colombier 		nf->qid = f->qid;
8359a747e4fSDavid du Colombier 		nf->user = strdup(f->user);
8369a747e4fSDavid du Colombier 		nf->c = f->c;
8379a747e4fSDavid du Colombier 		nf->wp = nf->buf;
8389a747e4fSDavid du Colombier 		nf->rp = nf->wp;
8399a747e4fSDavid du Colombier 		f = nf;
8409a747e4fSDavid du Colombier 	}
8419a747e4fSDavid du Colombier 
8429a747e4fSDavid du Colombier 	qid = f->qid;
8439a747e4fSDavid du Colombier 	err = nil;
8449a747e4fSDavid du Colombier 	nwname = r->f.nwname;
8459a747e4fSDavid du Colombier 	nqid = 0;
8469a747e4fSDavid du Colombier 	if(nwname > 0){
8479a747e4fSDavid du Colombier 		for(; err == nil && nqid < nwname; nqid++){
8489a747e4fSDavid du Colombier 			if(nqid >= MAXWELEM){
8499a747e4fSDavid du Colombier 				err = "too many name elements";
8509a747e4fSDavid du Colombier 				break;
8519a747e4fSDavid du Colombier 			}
8529a747e4fSDavid du Colombier 			name = r->f.wname[nqid];
8537dd7cddfSDavid du Colombier 			if(strcmp(name, "..") == 0)
8549a747e4fSDavid du Colombier 				qid = parentqid(qid);
8557dd7cddfSDavid du Colombier 			else if(strcmp(name, ".") != 0){
8567dd7cddfSDavid du Colombier 				for(i = 0; ; i++){
857cb3cefd4SDavid du Colombier 					n = fsdirgen(fs, qid, i, &d, nil, 0);
858cb3cefd4SDavid du Colombier 					if(n < 0){
8599a747e4fSDavid du Colombier 						err = Eexist;
8609a747e4fSDavid du Colombier 						break;
8617dd7cddfSDavid du Colombier 					}
862cb3cefd4SDavid du Colombier 					if(n > 0 && strcmp(name, d.name) == 0){
8639a747e4fSDavid du Colombier 						qid = d.qid;
8647dd7cddfSDavid du Colombier 						break;
8657dd7cddfSDavid du Colombier 					}
8667dd7cddfSDavid du Colombier 				}
8677dd7cddfSDavid du Colombier 			}
8689a747e4fSDavid du Colombier 			wqid[nqid] = qid;
8699a747e4fSDavid du Colombier 		}
8709a747e4fSDavid du Colombier 		if(nf != nil && nqid < nwname)
8719a747e4fSDavid du Colombier 			fsputfid(fs, nf);
8729a747e4fSDavid du Colombier 		if(nqid == nwname)
8739a747e4fSDavid du Colombier 			f->qid = qid;
8749a747e4fSDavid du Colombier 	}
8759a747e4fSDavid du Colombier 
8769a747e4fSDavid du Colombier 	memmove(r->f.wqid, wqid, nqid*sizeof(Qid));
8779a747e4fSDavid du Colombier 	r->f.nwqid = nqid;
8789a747e4fSDavid du Colombier 	fsreply(fs, r, err);
8797dd7cddfSDavid du Colombier }
8807dd7cddfSDavid du Colombier 
8817dd7cddfSDavid du Colombier int
ingroup(char * user,char * group)8827dd7cddfSDavid du Colombier ingroup(char *user, char *group)
8837dd7cddfSDavid du Colombier {
8847dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt;
8857dd7cddfSDavid du Colombier 	Ndbs s;
8867dd7cddfSDavid du Colombier 
8877dd7cddfSDavid du Colombier 	t = ndbsearch(db, &s, "group", group);
8887dd7cddfSDavid du Colombier 	if(t == nil)
8897dd7cddfSDavid du Colombier 		return 0;
8907dd7cddfSDavid du Colombier 	for(nt = t; nt; nt = nt->entry){
8917dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, "uid") == 0)
8927dd7cddfSDavid du Colombier 		if(strcmp(nt->val, user) == 0)
8937dd7cddfSDavid du Colombier 			break;
8947dd7cddfSDavid du Colombier 	}
8957dd7cddfSDavid du Colombier 	ndbfree(t);
8967dd7cddfSDavid du Colombier 	return nt != nil;
8977dd7cddfSDavid du Colombier }
8987dd7cddfSDavid du Colombier 
8997dd7cddfSDavid du Colombier int
userok(char * u,char * cname)9007dd7cddfSDavid du Colombier userok(char *u, char *cname)
9017dd7cddfSDavid du Colombier {
9027dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt;
9037dd7cddfSDavid du Colombier 	Ndbs s;
9047dd7cddfSDavid du Colombier 
9057dd7cddfSDavid du Colombier 	t = ndbsearch(db, &s, "console", cname);
9067dd7cddfSDavid du Colombier 	if(t == nil)
9077dd7cddfSDavid du Colombier 		return 0;
9087dd7cddfSDavid du Colombier 
9097dd7cddfSDavid du Colombier 	for(nt = t; nt; nt = nt->entry){
9107dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, "uid") == 0)
9117dd7cddfSDavid du Colombier 		if(strcmp(nt->val, u) == 0)
9127dd7cddfSDavid du Colombier 			break;
9137dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, "gid") == 0)
9147dd7cddfSDavid du Colombier 		if(ingroup(u, nt->val))
9157dd7cddfSDavid du Colombier 			break;
9167dd7cddfSDavid du Colombier 	}
9177dd7cddfSDavid du Colombier 	ndbfree(t);
9188bc54264SDavid du Colombier 
9197dd7cddfSDavid du Colombier 	return nt != nil;
9207dd7cddfSDavid du Colombier }
9217dd7cddfSDavid du Colombier 
9227dd7cddfSDavid du Colombier int m2p[] ={
9237dd7cddfSDavid du Colombier 	[OREAD]		4,
9247dd7cddfSDavid du Colombier 	[OWRITE]	2,
9257dd7cddfSDavid du Colombier 	[ORDWR]		6
9267dd7cddfSDavid du Colombier };
9277dd7cddfSDavid du Colombier 
9288bc54264SDavid du Colombier /*
9298bc54264SDavid du Colombier  *  broadcast a message to all listeners
9308bc54264SDavid du Colombier  */
9318bc54264SDavid du Colombier void
bcastmsg(Fs * fs,Console * c,char * msg,int n)9328bc54264SDavid du Colombier bcastmsg(Fs *fs, Console *c, char *msg, int n)
9338bc54264SDavid du Colombier {
9348bc54264SDavid du Colombier 	Fid *fl;
9358bc54264SDavid du Colombier 
9368bc54264SDavid du Colombier 	for(fl = c->flist; fl; fl = fl->cnext){
9378bc54264SDavid du Colombier 		fromconsole(fl, msg, n);
9388bc54264SDavid du Colombier 		fskick(fs, fl);
9398bc54264SDavid du Colombier 	}
9408bc54264SDavid du Colombier }
9418bc54264SDavid du Colombier 
9427dd7cddfSDavid du Colombier void
fsopen(Fs * fs,Request * r,Fid * f)9437dd7cddfSDavid du Colombier fsopen(Fs *fs, Request *r, Fid *f)
9447dd7cddfSDavid du Colombier {
9457dd7cddfSDavid du Colombier 	int mode;
9467dd7cddfSDavid du Colombier 	Console *c;
9477dd7cddfSDavid du Colombier 
9487dd7cddfSDavid du Colombier 	if(f->attached == 0){
9497dd7cddfSDavid du Colombier 		fsreply(fs, r, Enofid);
9507dd7cddfSDavid du Colombier 		return;
9517dd7cddfSDavid du Colombier 	}
9527dd7cddfSDavid du Colombier 
9537dd7cddfSDavid du Colombier 	if(f->open){
9547dd7cddfSDavid du Colombier 		fsreply(fs, r, Eisopen);
9557dd7cddfSDavid du Colombier 		return;
9567dd7cddfSDavid du Colombier 	}
9577dd7cddfSDavid du Colombier 
9587dd7cddfSDavid du Colombier 	mode = r->f.mode & 3;
9597dd7cddfSDavid du Colombier 
9609a747e4fSDavid du Colombier 	if((QTDIR & f->qid.type) && mode != OREAD){
9617dd7cddfSDavid du Colombier 		fsreply(fs, r, Eperm);
9627dd7cddfSDavid du Colombier 		return;
9637dd7cddfSDavid du Colombier 	}
9647dd7cddfSDavid du Colombier 
9657dd7cddfSDavid du Colombier 	switch(TYPE(f->qid)){
9667dd7cddfSDavid du Colombier 	case Qdata:
9677dd7cddfSDavid du Colombier 		c = fs->cons[CONS(f->qid)];
9687dd7cddfSDavid du Colombier 		if(!userok(f->user, c->name)){
9697dd7cddfSDavid du Colombier 			fsreply(fs, r, Eperm);
9707dd7cddfSDavid du Colombier 			return;
9717dd7cddfSDavid du Colombier 		}
9727dd7cddfSDavid du Colombier 		f->rp = f->buf;
9737dd7cddfSDavid du Colombier 		f->wp = f->buf;
9747dd7cddfSDavid du Colombier 		f->c = c;
9757dd7cddfSDavid du Colombier 		lock(c);
9768bc54264SDavid du Colombier 		sprint(f->mbuf, "[%s] ", f->user);
9778bc54264SDavid du Colombier 		f->bufn = strlen(f->mbuf);
9788bc54264SDavid du Colombier 		f->used = 0;
9797dd7cddfSDavid du Colombier 		f->cnext = c->flist;
9807dd7cddfSDavid du Colombier 		c->flist = f;
9817dd7cddfSDavid du Colombier 		bcastmembers(fs, c, "+", f);
9827dd7cddfSDavid du Colombier 		if(c->pid == 0)
9837dd7cddfSDavid du Colombier 			fsreopen(fs, c);
9847dd7cddfSDavid du Colombier 		unlock(c);
9857dd7cddfSDavid du Colombier 		break;
9867dd7cddfSDavid du Colombier 	case Qctl:
9877dd7cddfSDavid du Colombier 		c = fs->cons[CONS(f->qid)];
9887dd7cddfSDavid du Colombier 		if(!userok(f->user, c->name)){
9897dd7cddfSDavid du Colombier 			fsreply(fs, r, Eperm);
9907dd7cddfSDavid du Colombier 			return;
9917dd7cddfSDavid du Colombier 		}
9927dd7cddfSDavid du Colombier 		f->c = c;
9937dd7cddfSDavid du Colombier 		break;
9947dd7cddfSDavid du Colombier 	case Qstat:
9957dd7cddfSDavid du Colombier 		c = fs->cons[CONS(f->qid)];
9967dd7cddfSDavid du Colombier 		if(!userok(f->user, c->name)){
9977dd7cddfSDavid du Colombier 			fsreply(fs, r, Eperm);
9987dd7cddfSDavid du Colombier 			return;
9997dd7cddfSDavid du Colombier 		}
10007dd7cddfSDavid du Colombier 		f->c = c;
10017dd7cddfSDavid du Colombier 		break;
10027dd7cddfSDavid du Colombier 	}
10037dd7cddfSDavid du Colombier 
10047dd7cddfSDavid du Colombier 	f->open = 1;
10059a747e4fSDavid du Colombier 	r->f.iounit = messagesize-IOHDRSZ;
10067dd7cddfSDavid du Colombier 	r->f.qid = f->qid;
10077dd7cddfSDavid du Colombier 	fsreply(fs, r, nil);
10087dd7cddfSDavid du Colombier }
10097dd7cddfSDavid du Colombier 
10107dd7cddfSDavid du Colombier void
fscreate(Fs * fs,Request * r,Fid *)10117dd7cddfSDavid du Colombier fscreate(Fs *fs, Request *r, Fid*)
10127dd7cddfSDavid du Colombier {
10137dd7cddfSDavid du Colombier 	fsreply(fs, r, Eperm);
10147dd7cddfSDavid du Colombier }
10157dd7cddfSDavid du Colombier 
10167dd7cddfSDavid du Colombier void
fsread(Fs * fs,Request * r,Fid * f)10177dd7cddfSDavid du Colombier fsread(Fs *fs, Request *r, Fid *f)
10187dd7cddfSDavid du Colombier {
10199a747e4fSDavid du Colombier 	uchar *p, *e;
10209a747e4fSDavid du Colombier 	int i, m, off;
10219a747e4fSDavid du Colombier 	vlong offset;
10227dd7cddfSDavid du Colombier 	Dir d;
10239a747e4fSDavid du Colombier 	char sbuf[ERRMAX];
10247dd7cddfSDavid du Colombier 
10257dd7cddfSDavid du Colombier 	if(f->attached == 0){
10267dd7cddfSDavid du Colombier 		fsreply(fs, r, Enofid);
10277dd7cddfSDavid du Colombier 		return;
10287dd7cddfSDavid du Colombier 	}
10297dd7cddfSDavid du Colombier 
103022a127bbSDavid du Colombier 	if((int)r->f.count < 0){
10317dd7cddfSDavid du Colombier 		fsreply(fs, r, Ebadcount);
10327dd7cddfSDavid du Colombier 		return;
10337dd7cddfSDavid du Colombier 	}
10347dd7cddfSDavid du Colombier 
10359a747e4fSDavid du Colombier 	if(QTDIR & f->qid.type){
10369a747e4fSDavid du Colombier 		p = r->buf + IOHDRSZ;
10379a747e4fSDavid du Colombier 		e = p + r->f.count;
10389a747e4fSDavid du Colombier 		offset = r->f.offset;
10399a747e4fSDavid du Colombier 		off = 0;
10409a747e4fSDavid du Colombier 		for(i=0; p<e; i++, off+=m){
10419a747e4fSDavid du Colombier 			m = fsdirgen(fs, f->qid, i, &d, p, e-p);
1042cb3cefd4SDavid du Colombier 			if(m < 0)
10437dd7cddfSDavid du Colombier 				break;
1044cb3cefd4SDavid du Colombier 			if(m > BIT16SZ && off >= offset)
10459a747e4fSDavid du Colombier 				p += m;
10467dd7cddfSDavid du Colombier 		}
10479a747e4fSDavid du Colombier 		r->f.data = (char*)r->buf + IOHDRSZ;
10489a747e4fSDavid du Colombier 		r->f.count = (char*)p - r->f.data;
10497dd7cddfSDavid du Colombier 	} else {
10507dd7cddfSDavid du Colombier 		switch(TYPE(f->qid)){
10517dd7cddfSDavid du Colombier 		case Qdata:
10527dd7cddfSDavid du Colombier 			addreq(&f->r, r);
10537dd7cddfSDavid du Colombier 			fskick(fs, f);
10547dd7cddfSDavid du Colombier 			return;
10557dd7cddfSDavid du Colombier 		case Qctl:
10569a747e4fSDavid du Colombier 			r->f.data = (char*)r->buf+IOHDRSZ;
10577dd7cddfSDavid du Colombier 			r->f.count = 0;
10587dd7cddfSDavid du Colombier 			break;
10597dd7cddfSDavid du Colombier 		case Qstat:
10607dd7cddfSDavid du Colombier 			if(r->f.count > sizeof(sbuf))
10617dd7cddfSDavid du Colombier 				r->f.count = sizeof(sbuf);
10629a747e4fSDavid du Colombier 			i = pread(f->c->sfd, sbuf, r->f.count, r->f.offset);
10637dd7cddfSDavid du Colombier 			if(i < 0){
10649a747e4fSDavid du Colombier 				errstr(sbuf, sizeof sbuf);
10657dd7cddfSDavid du Colombier 				fsreply(fs, r, sbuf);
10667dd7cddfSDavid du Colombier 				return;
10677dd7cddfSDavid du Colombier 			}
10687dd7cddfSDavid du Colombier 			r->f.data = sbuf;
10697dd7cddfSDavid du Colombier 			r->f.count = i;
10707dd7cddfSDavid du Colombier 			break;
10717dd7cddfSDavid du Colombier 		default:
10727dd7cddfSDavid du Colombier 			fsreply(fs, r, Eexist);
10737dd7cddfSDavid du Colombier 			return;
10747dd7cddfSDavid du Colombier 		}
10757dd7cddfSDavid du Colombier 	}
10767dd7cddfSDavid du Colombier 	fsreply(fs, r, nil);
10777dd7cddfSDavid du Colombier }
10787dd7cddfSDavid du Colombier 
10797dd7cddfSDavid du Colombier void
fswrite(Fs * fs,Request * r,Fid * f)10807dd7cddfSDavid du Colombier fswrite(Fs *fs, Request *r, Fid *f)
10817dd7cddfSDavid du Colombier {
10828bc54264SDavid du Colombier 	int i, eol = 0;
10837dd7cddfSDavid du Colombier 
10847dd7cddfSDavid du Colombier 	if(f->attached == 0){
10857dd7cddfSDavid du Colombier 		fsreply(fs, r, Enofid);
10867dd7cddfSDavid du Colombier 		return;
10877dd7cddfSDavid du Colombier 	}
10887dd7cddfSDavid du Colombier 
108922a127bbSDavid du Colombier 	if((int)r->f.count < 0){
10907dd7cddfSDavid du Colombier 		fsreply(fs, r, Ebadcount);
10917dd7cddfSDavid du Colombier 		return;
10927dd7cddfSDavid du Colombier 	}
10937dd7cddfSDavid du Colombier 
10949a747e4fSDavid du Colombier 	if(QTDIR & f->qid.type){
10957dd7cddfSDavid du Colombier 		fsreply(fs, r, Eperm);
10967dd7cddfSDavid du Colombier 		return;
10977dd7cddfSDavid du Colombier 	}
10987dd7cddfSDavid du Colombier 
10997dd7cddfSDavid du Colombier 	switch(TYPE(f->qid)){
11007dd7cddfSDavid du Colombier 	default:
11017dd7cddfSDavid du Colombier 		fsreply(fs, r, Eperm);
11027dd7cddfSDavid du Colombier 		return;
11037dd7cddfSDavid du Colombier 	case Qctl:
11047dd7cddfSDavid du Colombier 		write(f->c->cfd, r->f.data, r->f.count);
11057dd7cddfSDavid du Colombier 		break;
11067dd7cddfSDavid du Colombier 	case Qdata:
11078bc54264SDavid du Colombier 		for(i = 0; i < r->f.count; i++){
11088bc54264SDavid du Colombier 			if(r->f.data[i] == '\n'){
11098bc54264SDavid du Colombier 				if(f->c->chat && f->used)
11108bc54264SDavid du Colombier 					eol = 1;
11117dd7cddfSDavid du Colombier 				if(f->c->cronly)
11127dd7cddfSDavid du Colombier 					r->f.data[i] = '\r';
11138bc54264SDavid du Colombier 			}
11148bc54264SDavid du Colombier 			else
11158bc54264SDavid du Colombier 				f->used = 1;
11168bc54264SDavid du Colombier 		}
11178bc54264SDavid du Colombier 		if(f->c->chat){
11188bc54264SDavid du Colombier 			fskick(fs, f);
11198bc54264SDavid du Colombier 			if(!f->used)
11208bc54264SDavid du Colombier 				break;
11218bc54264SDavid du Colombier 
11228bc54264SDavid du Colombier 			if(f->bufn + r->f.count > Bufsize){
11238bc54264SDavid du Colombier 				r->f.count -= (f->bufn + r->f.count) % Bufsize;
11248bc54264SDavid du Colombier 				eol = 1;
11258bc54264SDavid du Colombier 			}
11268bc54264SDavid du Colombier 			strncat(f->mbuf, r->f.data, r->f.count);
11278bc54264SDavid du Colombier 			f->bufn += r->f.count;
11288bc54264SDavid du Colombier 			if(eol){
11298bc54264SDavid du Colombier 				bcastmsg(fs, f->c, f->mbuf, f->bufn);
11308bc54264SDavid du Colombier 				sprint(f->mbuf, "[%s] ", f->user);
11318bc54264SDavid du Colombier 				f->bufn = strlen(f->mbuf);
11328bc54264SDavid du Colombier 				f->used = 0;
11338bc54264SDavid du Colombier 			}
11348bc54264SDavid du Colombier 		}
11358bc54264SDavid du Colombier 		else
11367dd7cddfSDavid du Colombier 			write(f->c->fd, r->f.data, r->f.count);
11377dd7cddfSDavid du Colombier 		break;
11387dd7cddfSDavid du Colombier 	}
11397dd7cddfSDavid du Colombier 	fsreply(fs, r, nil);
11407dd7cddfSDavid du Colombier }
11417dd7cddfSDavid du Colombier 
11427dd7cddfSDavid du Colombier void
fsclunk(Fs * fs,Request * r,Fid * f)11437dd7cddfSDavid du Colombier fsclunk(Fs *fs, Request *r, Fid *f)
11447dd7cddfSDavid du Colombier {
11457dd7cddfSDavid du Colombier 	Fid **l, *fl;
11467dd7cddfSDavid du Colombier 	Request *nr;
11477dd7cddfSDavid du Colombier 
11487dd7cddfSDavid du Colombier 	if(f->open && TYPE(f->qid) == Qdata){
11497dd7cddfSDavid du Colombier 		while((nr = remreq(&f->r)) != nil){
11507dd7cddfSDavid du Colombier 			fsputfid(fs, f);
11517dd7cddfSDavid du Colombier 			free(nr);
11527dd7cddfSDavid du Colombier 		}
11537dd7cddfSDavid du Colombier 
11547dd7cddfSDavid du Colombier 		lock(f->c);
11557dd7cddfSDavid du Colombier 		for(l = &f->c->flist; *l; l = &fl->cnext){
11567dd7cddfSDavid du Colombier 			fl = *l;
11577dd7cddfSDavid du Colombier 			if(fl == f){
11587dd7cddfSDavid du Colombier 				*l = fl->cnext;
11597dd7cddfSDavid du Colombier 				break;
11607dd7cddfSDavid du Colombier 			}
11617dd7cddfSDavid du Colombier 		}
11627dd7cddfSDavid du Colombier 		bcastmembers(fs, f->c, "-", f);
11637dd7cddfSDavid du Colombier 		if(f->c->ondemand && f->c->flist == nil)
11647dd7cddfSDavid du Colombier 			fsreopen(fs, f->c);
11657dd7cddfSDavid du Colombier 		unlock(f->c);
11667dd7cddfSDavid du Colombier 	}
11677dd7cddfSDavid du Colombier 	fsreply(fs, r, nil);
11687dd7cddfSDavid du Colombier 	fsputfid(fs, f);
11697dd7cddfSDavid du Colombier }
11707dd7cddfSDavid du Colombier 
11717dd7cddfSDavid du Colombier void
fsremove(Fs * fs,Request * r,Fid *)11727dd7cddfSDavid du Colombier fsremove(Fs *fs, Request *r, Fid*)
11737dd7cddfSDavid du Colombier {
11747dd7cddfSDavid du Colombier 	fsreply(fs, r, Eperm);
11757dd7cddfSDavid du Colombier }
11767dd7cddfSDavid du Colombier 
11777dd7cddfSDavid du Colombier void
fsstat(Fs * fs,Request * r,Fid * f)11787dd7cddfSDavid du Colombier fsstat(Fs *fs, Request *r, Fid *f)
11797dd7cddfSDavid du Colombier {
118022a127bbSDavid du Colombier 	int i, n;
11817dd7cddfSDavid du Colombier 	Qid q;
11827dd7cddfSDavid du Colombier 	Dir d;
11837dd7cddfSDavid du Colombier 
11847dd7cddfSDavid du Colombier 	q = parentqid(f->qid);
11857dd7cddfSDavid du Colombier 	for(i = 0; ; i++){
11869a747e4fSDavid du Colombier 		r->f.stat = r->buf+IOHDRSZ;
118722a127bbSDavid du Colombier 		n = fsdirgen(fs, q, i, &d, r->f.stat, messagesize-IOHDRSZ);
118822a127bbSDavid du Colombier 		if(n < 0){
11897dd7cddfSDavid du Colombier 			fsreply(fs, r, Eexist);
11907dd7cddfSDavid du Colombier 			return;
11917dd7cddfSDavid du Colombier 		}
119222a127bbSDavid du Colombier 		r->f.nstat = n;
1193cb3cefd4SDavid du Colombier 		if(r->f.nstat > BIT16SZ && d.qid.path == f->qid.path)
11947dd7cddfSDavid du Colombier 			break;
11957dd7cddfSDavid du Colombier 	}
11967dd7cddfSDavid du Colombier 	fsreply(fs, r, nil);
11977dd7cddfSDavid du Colombier }
11987dd7cddfSDavid du Colombier 
11997dd7cddfSDavid du Colombier void
fswstat(Fs * fs,Request * r,Fid *)12007dd7cddfSDavid du Colombier fswstat(Fs *fs, Request *r, Fid*)
12017dd7cddfSDavid du Colombier {
12027dd7cddfSDavid du Colombier 	fsreply(fs, r, Eperm);
12037dd7cddfSDavid du Colombier }
12047dd7cddfSDavid du Colombier 
12057dd7cddfSDavid du Colombier void
fsreply(Fs * fs,Request * r,char * err)12067dd7cddfSDavid du Colombier fsreply(Fs *fs, Request *r, char *err)
12077dd7cddfSDavid du Colombier {
12087dd7cddfSDavid du Colombier 	int n;
12099a747e4fSDavid du Colombier 	uchar buf[8192+IOHDRSZ];
12107dd7cddfSDavid du Colombier 
12117dd7cddfSDavid du Colombier 	if(err){
12127dd7cddfSDavid du Colombier 		r->f.type = Rerror;
12139a747e4fSDavid du Colombier 		r->f.ename = err;
12147dd7cddfSDavid du Colombier 	}
12159a747e4fSDavid du Colombier 	n = convS2M(&r->f, buf, messagesize);
12167dd7cddfSDavid du Colombier 	if(debug)
12179a747e4fSDavid du Colombier 		fprint(2, "%F path %llux n=%d\n", &r->f, r->fid->qid.path, n);
12187dd7cddfSDavid du Colombier 	fsputfid(fs, r->fid);
12199a747e4fSDavid du Colombier 	if(write(fs->fd, buf, n) != n)
12207dd7cddfSDavid du Colombier 		fatal("unmounted");
12217dd7cddfSDavid du Colombier 	free(r);
12227dd7cddfSDavid du Colombier }
12237dd7cddfSDavid du Colombier 
12247dd7cddfSDavid du Colombier /*
12257dd7cddfSDavid du Colombier  *  called whenever input or a read request has been received
12267dd7cddfSDavid du Colombier  */
12277dd7cddfSDavid du Colombier void
fskick(Fs * fs,Fid * f)12287dd7cddfSDavid du Colombier fskick(Fs *fs, Fid *f)
12297dd7cddfSDavid du Colombier {
12307dd7cddfSDavid du Colombier 	Request *r;
12317dd7cddfSDavid du Colombier 	char *p, *rp, *wp, *ep;
12327dd7cddfSDavid du Colombier 	int i;
12337dd7cddfSDavid du Colombier 
12347dd7cddfSDavid du Colombier 	lock(f);
12357dd7cddfSDavid du Colombier 	while(f->rp != f->wp){
12367dd7cddfSDavid du Colombier 		r = remreq(&f->r);
12377dd7cddfSDavid du Colombier 		if(r == nil)
12387dd7cddfSDavid du Colombier 			break;
12399a747e4fSDavid du Colombier 		p = (char*)r->buf;
12407dd7cddfSDavid du Colombier 		rp = f->rp;
12417dd7cddfSDavid du Colombier 		wp = f->wp;
12427dd7cddfSDavid du Colombier 		ep = &f->buf[Bufsize];
12437dd7cddfSDavid du Colombier 		for(i = 0; i < r->f.count && rp != wp; i++){
12447dd7cddfSDavid du Colombier 			*p++ = *rp++;
12457dd7cddfSDavid du Colombier 			if(rp >= ep)
12467dd7cddfSDavid du Colombier 				rp = f->buf;
12477dd7cddfSDavid du Colombier 		}
12487dd7cddfSDavid du Colombier 		f->rp = rp;
12499a747e4fSDavid du Colombier 		r->f.data = (char*)r->buf;
12509a747e4fSDavid du Colombier 		r->f.count = p - (char*)r->buf;
12517dd7cddfSDavid du Colombier 		fsreply(fs, r, nil);
12527dd7cddfSDavid du Colombier 	}
12537dd7cddfSDavid du Colombier 	unlock(f);
12547dd7cddfSDavid du Colombier }
12557dd7cddfSDavid du Colombier 
12567dd7cddfSDavid du Colombier void
usage(void)12577dd7cddfSDavid du Colombier usage(void)
12587dd7cddfSDavid du Colombier {
12597dd7cddfSDavid du Colombier 	fprint(2, "usage: consolefs [-d] [-m mount-point] [-c console-db]\n");
12607dd7cddfSDavid du Colombier 	threadexitsall("usage");
12617dd7cddfSDavid du Colombier }
12627dd7cddfSDavid du Colombier 
12637dd7cddfSDavid du Colombier void
threadmain(int argc,char ** argv)12647dd7cddfSDavid du Colombier threadmain(int argc, char **argv)
12657dd7cddfSDavid du Colombier {
1266*8498559bSDavid du Colombier 	rfork(RFNOTEG);
12679a747e4fSDavid du Colombier 	fmtinstall('F', fcallfmt);
12687dd7cddfSDavid du Colombier 
12697dd7cddfSDavid du Colombier 	ARGBEGIN{
12707dd7cddfSDavid du Colombier 	case 'd':
12717dd7cddfSDavid du Colombier 		debug++;
12727dd7cddfSDavid du Colombier 		break;
12737dd7cddfSDavid du Colombier 	case 'c':
12747dd7cddfSDavid du Colombier 		consoledb = ARGF();
12757dd7cddfSDavid du Colombier 		if(consoledb == nil)
12767dd7cddfSDavid du Colombier 			usage();
12777dd7cddfSDavid du Colombier 		break;
12787dd7cddfSDavid du Colombier 	case 'm':
12797dd7cddfSDavid du Colombier 		mntpt = ARGF();
12807dd7cddfSDavid du Colombier 		if(mntpt == nil)
12817dd7cddfSDavid du Colombier 			usage();
12827dd7cddfSDavid du Colombier 		break;
12837dd7cddfSDavid du Colombier 	}ARGEND;
12847dd7cddfSDavid du Colombier 
12857dd7cddfSDavid du Colombier 	db = ndbopen(consoledb);
12867dd7cddfSDavid du Colombier 	if(db == nil)
12877dd7cddfSDavid du Colombier  		fatal("can't open %s: %r", consoledb);
12887dd7cddfSDavid du Colombier 
12897dd7cddfSDavid du Colombier 	fsmount(mntpt);
12907dd7cddfSDavid du Colombier }
1291