709 lines · 13.4 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include <draw.h>#include <thread.h>#include <cursor.h>#include <mouse.h>#include <keyboard.h>#include <frame.h>#include <fcall.h>#include "dat.h"#include "fns.h" char Eperm[] = "permission denied";char Eexist[] = "file does not exist";char Enotdir[] = "not a directory";char	Ebadfcall[] = "bad fcall type";char	Eoffset[] = "illegal offset"; int	messagesize = 8192+IOHDRSZ;	/* good start */ enum{	DEBUG = 0}; Dirtab dirtab[]={	{ ".",			QTDIR,	Qdir,			0500|DMDIR },	{ "cons",		QTFILE,	Qcons,		0600 },	{ "cursor",		QTFILE,	Qcursor,		0600 },	{ "consctl",	QTFILE,	Qconsctl,		0200 },	{ "winid",		QTFILE,	Qwinid,		0400 },	{ "winname",	QTFILE,	Qwinname,	0400 },	{ "kbdin",		QTFILE,	Qkbdin,		0200 },	{ "label",		QTFILE,	Qlabel,		0600 },	{ "mouse",	QTFILE,	Qmouse,		0600 },	{ "screen",		QTFILE,	Qscreen,		0400 },	{ "snarf",		QTFILE,	Qsnarf,		0600 },	{ "text",		QTFILE,	Qtext,		0400 },	{ "wdir",		QTFILE,	Qwdir,		0600 },	{ "wctl",		QTFILE,	Qwctl,		0600 },	{ "window",	QTFILE,	Qwindow,		0400 },	{ "wsys",		QTDIR,	Qwsys,		0500|DMDIR },	{ nil, }}; static uint		getclock(void);static void		filsysproc(void*);static Fid*		newfid(Filsys*, int);static int		dostat(Filsys*, int, Dirtab*, uchar*, int, uint); int	clockfd;int	firstmessage = 1; char	srvpipe[64];char	srvwctl[64]; static	Xfid*	filsysflush(Filsys*, Xfid*, Fid*);static	Xfid*	filsysversion(Filsys*, Xfid*, Fid*);static	Xfid*	filsysauth(Filsys*, Xfid*, Fid*);static	Xfid*	filsysnop(Filsys*, Xfid*, Fid*);static	Xfid*	filsysattach(Filsys*, Xfid*, Fid*);static	Xfid*	filsyswalk(Filsys*, Xfid*, Fid*);static	Xfid*	filsysopen(Filsys*, Xfid*, Fid*);static	Xfid*	filsyscreate(Filsys*, Xfid*, Fid*);static	Xfid*	filsysread(Filsys*, Xfid*, Fid*);static	Xfid*	filsyswrite(Filsys*, Xfid*, Fid*);static	Xfid*	filsysclunk(Filsys*, Xfid*, Fid*);static	Xfid*	filsysremove(Filsys*, Xfid*, Fid*);static	Xfid*	filsysstat(Filsys*, Xfid*, Fid*);static	Xfid*	filsyswstat(Filsys*, Xfid*, Fid*); Xfid* 	(*fcall[Tmax])(Filsys*, Xfid*, Fid*) ={	[Tflush]	= filsysflush,	[Tversion]	= filsysversion,	[Tauth]	= filsysauth,	[Tattach]	= filsysattach,	[Twalk]	= filsyswalk,	[Topen]	= filsysopen,	[Tcreate]	= filsyscreate,	[Tread]	= filsysread,	[Twrite]	= filsyswrite,	[Tclunk]	= filsysclunk,	[Tremove]= filsysremove,	[Tstat]	= filsysstat,	[Twstat]	= filsyswstat,}; voidpost(char *name, char *envname, int srvfd){	int fd;	char buf[32]; 	fd = create(name, OWRITE|ORCLOSE|OCEXEC, 0600);	if(fd < 0)		error(name);	sprint(buf, "%d",srvfd);	if(write(fd, buf, strlen(buf)) != strlen(buf))		error("srv write");	putenv(envname, name);} /* * Build pipe with OCEXEC set on second fd. * Can't put it on both because we want to post one in /srv. */intcexecpipe(int *p0, int *p1){	/* pipe the hard way to get close on exec */	if(bind("#|", "/mnt/temp", MREPL) < 0)		return -1;	*p0 = open("/mnt/temp/data", ORDWR);	*p1 = open("/mnt/temp/data1", ORDWR|OCEXEC);	unmount(nil, "/mnt/temp");	if(*p0<0 || *p1<0)		return -1;	return 0;} Filsys*filsysinit(Channel *cxfidalloc){	int n, fd, pid, p0;	Filsys *fs;	Channel *c;	char buf[128]; 	fs = emalloc(sizeof(Filsys));	if(cexecpipe(&fs->cfd, &fs->sfd) < 0)		goto Rescue;	fmtinstall('F', fcallfmt);	clockfd = open("/dev/time", OREAD|OCEXEC);	fd = open("/dev/user", OREAD);	strcpy(buf, "Jean-Paul_Belmondo");	if(fd >= 0){		n = read(fd, buf, sizeof buf-1);		if(n > 0)			buf[n] = 0;		close(fd);	}	fs->user = estrdup(buf);	fs->cxfidalloc = cxfidalloc;	pid = getpid(); 	/*	 * Create and post wctl pipe	 */	if(cexecpipe(&p0, &wctlfd) < 0)		goto Rescue;	sprint(srvwctl, "/srv/riowctl.%s.%d", fs->user, pid);	post(srvwctl, "wctl", p0);	close(p0); 	/*	 * Start server processes	 */	c = chancreate(sizeof(char*), 0);	if(c == nil)		error("wctl channel");	proccreate(wctlproc, c, 4096);	threadcreate(wctlthread, c, 4096);	proccreate(filsysproc, fs, 10000); 	/*	 * Post srv pipe	 */	sprint(srvpipe, "/srv/rio.%s.%d", fs->user, pid);	post(srvpipe, "wsys", fs->cfd); 	return fs; Rescue:	free(fs);	return nil;} staticvoidfilsysproc(void *arg){	int n;	Xfid *x;	Fid *f;	Fcall t;	uchar *buf;	Filsys *fs; 	threadsetname("FILSYSPROC");	fs = arg;	fs->pid = getpid();	x = nil;	for(;;){		buf = emalloc(messagesize+UTFmax);	/* UTFmax for appending partial rune in xfidwrite */		n = read9pmsg(fs->sfd, buf, messagesize);		if(n <= 0){			yield();	/* if threadexitsall'ing, will not return */			fprint(2, "rio: %d: read9pmsg: %d %r\n", getpid(), n);			errorshouldabort = 0;			error("eof or i/o error on server channel");		}		if(x == nil){			send(fs->cxfidalloc, nil);			recv(fs->cxfidalloc, &x);			x->fs = fs;		}		x->buf = buf;		if(convM2S(buf, n, x) != n)			error("convert error in convM2S");		if(DEBUG)			fprint(2, "rio:<-%F\n", &x->Fcall);		if(fcall[x->type] == nil)			x = filsysrespond(fs, x, &t, Ebadfcall);		else{			if(x->type==Tversion || x->type==Tauth)				f = nil;			else				f = newfid(fs, x->fid);			x->f = f;			x  = (*fcall[x->type])(fs, x, f);		}		firstmessage = 0;	}} /* * Called only from a different FD group */intfilsysmount(Filsys *fs, int id){	char buf[32]; 	close(fs->sfd);	/* close server end so mount won't hang if exiting */	sprint(buf, "%d", id);	if(mount(fs->cfd, -1, "/mnt/wsys", MREPL, buf) < 0){		fprint(2, "mount failed: %r\n");		return -1;	}	if(bind("/mnt/wsys", "/dev", MBEFORE) < 0){		fprint(2, "bind failed: %r\n");		return -1;	}	return 0;} Xfid*filsysrespond(Filsys *fs, Xfid *x, Fcall *t, char *err){	int n; 	if(err){		t->type = Rerror;		t->ename = err;	}else		t->type = x->type+1;	t->fid = x->fid;	t->tag = x->tag;	if(x->buf == nil)		x->buf = malloc(messagesize);	n = convS2M(t, x->buf, messagesize);	if(n <= 0)		error("convert error in convS2M");	if(write(fs->sfd, x->buf, n) != n)		error("write error in respond");	if(DEBUG)		fprint(2, "rio:->%F\n", t);	free(x->buf);	x->buf = nil;	return x;} voidfilsyscancel(Xfid *x){	if(x->buf){		free(x->buf);		x->buf = nil;	}} staticXfid*filsysversion(Filsys *fs, Xfid *x, Fid*){	Fcall t; 	if(!firstmessage)		return filsysrespond(x->fs, x, &t, "version request not first message");	if(x->msize < 256)		return filsysrespond(x->fs, x, &t, "version: message size too small");	messagesize = x->msize;	t.msize = messagesize;	if(strncmp(x->version, "9P2000", 6) != 0)		return filsysrespond(x->fs, x, &t, "unrecognized 9P version");	t.version = "9P2000";	return filsysrespond(fs, x, &t, nil);} staticXfid*filsysauth(Filsys *fs, Xfid *x, Fid*){	Fcall t; 		return filsysrespond(fs, x, &t, "rio: authentication not required");} staticXfid*filsysflush(Filsys*, Xfid *x, Fid*){	sendp(x->c, xfidflush);	return nil;} staticXfid*filsysattach(Filsys *, Xfid *x, Fid *f){	Fcall t; 	if(strcmp(x->uname, x->fs->user) != 0)		return filsysrespond(x->fs, x, &t, Eperm);	f->busy = TRUE;	f->open = FALSE;	f->qid.path = Qdir;	f->qid.type = QTDIR;	f->qid.vers = 0;	f->dir = dirtab;	f->nrpart = 0;	sendp(x->c, xfidattach);	return nil;} staticintnumeric(char *s){	for(; *s!='\0'; s++)		if(*s<'0' || '9'<*s)			return 0;	return 1;} staticXfid*filsyswalk(Filsys *fs, Xfid *x, Fid *f){	Fcall t;	Fid *nf;	int i, id;	uchar type;	ulong path;	Dirtab *d, *dir;	Window *w;	char *err;	Qid qid; 	if(f->open)		return filsysrespond(fs, x, &t, "walk of open file");	nf = nil;	if(x->fid  != x->newfid){		/* BUG: check exists */		nf = newfid(fs, x->newfid);		if(nf->busy)			return filsysrespond(fs, x, &t, "clone to busy fid");		nf->busy = TRUE;		nf->open = FALSE;		nf->dir = f->dir;		nf->qid = f->qid;		nf->w = f->w;		incref(f->w);		nf->nrpart = 0;	/* not open, so must be zero */		f = nf;	/* walk f */	} 	t.nwqid = 0;	err = nil; 	/* update f->qid, f->dir only if walk completes */	qid = f->qid;	dir = f->dir; 	if(x->nwname > 0){		for(i=0; i<x->nwname; i++){			if((qid.type & QTDIR) == 0){				err = Enotdir;				break;			}			if(strcmp(x->wname[i], "..") == 0){				type = QTDIR;				path = Qdir;				dir = dirtab;				if(FILE(qid) == Qwsysdir)					path = Qwsys;				id = 0;    Accept:				if(i == MAXWELEM){					err = "name too long";					break;				}				qid.type = type;				qid.vers = 0;				qid.path = QID(id, path);				t.wqid[t.nwqid++] = qid;				continue;			} 			if(qid.path == Qwsys){				/* is it a numeric name? */				if(!numeric(x->wname[i]))					break;				/* yes: it's a directory */				id = atoi(x->wname[i]);				qlock(&all);				w = wlookid(id);				if(w == nil){					qunlock(&all);					break;				}				path = Qwsysdir;				type = QTDIR;				qunlock(&all);				incref(w);				sendp(winclosechan, f->w);				f->w = w;				dir = dirtab;				goto Accept;			}					if(snarffd>=0 && strcmp(x->wname[i], "snarf")==0)				break;	/* don't serve /dev/snarf if it's provided in the environment */			id = WIN(f->qid);			d = dirtab;			d++;	/* skip '.' */			for(; d->name; d++)				if(strcmp(x->wname[i], d->name) == 0){					path = d->qid;					type = d->type;					dir = d;					goto Accept;				} 			break;	/* file not found */		} 		if(i==0 && err==nil)			err = Eexist;	} 	if(err!=nil || t.nwqid<x->nwname){		if(nf){			if(nf->w)				sendp(winclosechan, nf->w);			nf->open = FALSE;			nf->busy = FALSE;		}	}else if(t.nwqid == x->nwname){		f->dir = dir;		f->qid = qid;	} 	return filsysrespond(fs, x, &t, err);} staticXfid*filsysopen(Filsys *fs, Xfid *x, Fid *f){	Fcall t;	int m; 	/* can't truncate anything, so just disregard */	x->mode &= ~(OTRUNC|OCEXEC);	/* can't execute or remove anything */	if(x->mode==OEXEC || (x->mode&ORCLOSE))		goto Deny;	switch(x->mode){	default:		goto Deny;	case OREAD:		m = 0400;		break;	case OWRITE:		m = 0200;		break;	case ORDWR:		m = 0600;		break;

Lines 1–500 of 709.