13 char Eperm[] = "permission denied";
14 char Eexist[] = "file does not exist";
15 char Enotdir[] = "not a directory";
16 char Ebadfcall[] = "bad fcall type";
17 char Eoffset[] = "illegal offset";
19 int messagesize = 8192+IOHDRSZ; /* good start */
27 { ".", QTDIR, Qdir, 0500|DMDIR },
28 { "cons", QTFILE, Qcons, 0600 },
29 { "cursor", QTFILE, Qcursor, 0600 },
30 { "consctl", QTFILE, Qconsctl, 0200 },
31 { "winid", QTFILE, Qwinid, 0400 },
32 { "winname", QTFILE, Qwinname, 0400 },
33 { "kbdin", QTFILE, Qkbdin, 0200 },
34 { "label", QTFILE, Qlabel, 0600 },
35 { "kbd", QTFILE, Qkbd, 0600 },
36 { "mouse", QTFILE, Qmouse, 0600 },
37 { "screen", QTFILE, Qscreen, 0400 },
38 { "snarf", QTFILE, Qsnarf, 0600 },
39 { "text", QTFILE, Qtext, 0400 },
40 { "wdir", QTFILE, Qwdir, 0600 },
41 { "wctl", QTFILE, Qwctl, 0600 },
42 { "window", QTFILE, Qwindow, 0400 },
43 { "wsys", QTDIR, Qwsys, 0500|DMDIR },
47 static uint getclock(void);
48 static void filsysproc(void*);
49 static Fid* newfid(Filsys*, int);
50 static int dostat(Filsys*, int, Dirtab*, uchar*, int, uint);
58 static Xfid* filsysflush(Filsys*, Xfid*, Fid*);
59 static Xfid* filsysversion(Filsys*, Xfid*, Fid*);
60 static Xfid* filsysauth(Filsys*, Xfid*, Fid*);
61 static Xfid* filsysnop(Filsys*, Xfid*, Fid*);
62 static Xfid* filsysattach(Filsys*, Xfid*, Fid*);
63 static Xfid* filsyswalk(Filsys*, Xfid*, Fid*);
64 static Xfid* filsysopen(Filsys*, Xfid*, Fid*);
65 static Xfid* filsyscreate(Filsys*, Xfid*, Fid*);
66 static Xfid* filsysread(Filsys*, Xfid*, Fid*);
67 static Xfid* filsyswrite(Filsys*, Xfid*, Fid*);
68 static Xfid* filsysclunk(Filsys*, Xfid*, Fid*);
69 static Xfid* filsysremove(Filsys*, Xfid*, Fid*);
70 static Xfid* filsysstat(Filsys*, Xfid*, Fid*);
71 static Xfid* filsyswstat(Filsys*, Xfid*, Fid*);
73 Xfid* (*fcall[Tmax])(Filsys*, Xfid*, Fid*) =
75 [Tflush] = filsysflush,
76 [Tversion] = filsysversion,
78 [Tattach] = filsysattach,
81 [Tcreate] = filsyscreate,
83 [Twrite] = filsyswrite,
84 [Tclunk] = filsysclunk,
85 [Tremove]= filsysremove,
87 [Twstat] = filsyswstat,
91 post(char *name, char *envname, int srvfd)
96 fd = create(name, OWRITE|ORCLOSE|OCEXEC, 0600);
99 snprint(buf, sizeof(buf), "%d", srvfd);
100 if(write(fd, buf, strlen(buf)) != strlen(buf))
102 putenv(envname, name);
106 * Build pipe with OCEXEC set on second fd.
107 * Can't put it on both because we want to post one in /srv.
110 cexecpipe(int *p0, int *p1)
112 /* pipe the hard way to get close on exec */
113 if(bind("#|", "/mnt/temp", MREPL) < 0)
115 *p0 = open("/mnt/temp/data", ORDWR);
116 *p1 = open("/mnt/temp/data1", ORDWR|OCEXEC);
117 unmount(nil, "/mnt/temp");
124 filsysinit(Channel *cxfidalloc)
131 fs = emalloc(sizeof(Filsys));
132 if(cexecpipe(&fs->cfd, &fs->sfd) < 0)
134 fmtinstall('F', fcallfmt);
135 clockfd = open("/dev/time", OREAD|OCEXEC);
136 fd = open("/dev/user", OREAD);
137 strcpy(buf, "Jean-Paul_Belmondo");
139 n = read(fd, buf, sizeof buf-1);
144 fs->user = estrdup(buf);
145 fs->cxfidalloc = cxfidalloc;
149 * Create and post wctl pipe
151 if(cexecpipe(&p0, &wctlfd) < 0)
153 snprint(srvwctl, sizeof(srvwctl), "/srv/riowctl.%s.%d", fs->user, pid);
154 post(srvwctl, "wctl", p0);
158 * Start server processes
160 c = chancreate(sizeof(char*), 0);
162 error("wctl channel");
163 proccreate(wctlproc, c, 4096);
164 threadcreate(wctlthread, c, 4096);
165 proccreate(filsysproc, fs, 10000);
170 snprint(srvpipe, sizeof(srvpipe), "/srv/rio.%s.%d", fs->user, pid);
171 post(srvpipe, "wsys", fs->cfd);
182 filsysproc(void *arg)
191 threadsetname("FILSYSPROC");
196 buf = emalloc(messagesize+UTFmax); /* UTFmax for appending partial rune in xfidwrite */
197 n = read9pmsg(fs->sfd, buf, messagesize);
199 yield(); /* if threadexitsall'ing, will not return */
200 fprint(2, "rio: %d: read9pmsg: %d %r\n", getpid(), n);
201 errorshouldabort = 0;
202 error("eof or i/o error on server channel");
205 send(fs->cxfidalloc, nil);
206 recv(fs->cxfidalloc, &x);
210 if(convM2S(buf, n, x) != n)
211 error("convert error in convM2S");
213 fprint(2, "rio:<-%F\n", &x->Fcall);
214 if(fcall[x->type] == nil)
215 x = filsysrespond(fs, x, &t, Ebadfcall);
217 if(x->type==Tversion || x->type==Tauth)
220 f = newfid(fs, x->fid);
222 x = (*fcall[x->type])(fs, x, f);
229 * Called only from a different FD group
232 filsysmount(Filsys *fs, int id)
236 close(fs->sfd); /* close server end so mount won't hang if exiting */
237 sprint(buf, "%d", id);
238 if(mount(fs->cfd, -1, "/mnt/wsys", MREPL, buf) < 0){
239 fprint(2, "mount failed: %r\n");
242 if(bind("/mnt/wsys", "/dev", MBEFORE) < 0){
243 fprint(2, "bind failed: %r\n");
250 filsysrespond(Filsys *fs, Xfid *x, Fcall *t, char *err)
262 x->buf = malloc(messagesize);
263 n = convS2M(t, x->buf, messagesize);
265 error("convert error in convS2M");
266 if(write(fs->sfd, x->buf, n) != n)
267 error("write error in respond");
269 fprint(2, "rio:->%F\n", t);
276 filsyscancel(Xfid *x)
286 filsysversion(Filsys *fs, Xfid *x, Fid*)
291 return filsysrespond(x->fs, x, &t, "version request not first message");
293 return filsysrespond(x->fs, x, &t, "version: message size too small");
294 messagesize = x->msize;
295 t.msize = messagesize;
296 if(strncmp(x->version, "9P2000", 6) != 0)
297 return filsysrespond(x->fs, x, &t, "unrecognized 9P version");
298 t.version = "9P2000";
299 return filsysrespond(fs, x, &t, nil);
304 filsysauth(Filsys *fs, Xfid *x, Fid*)
308 return filsysrespond(fs, x, &t, "rio: authentication not required");
313 filsysflush(Filsys*, Xfid *x, Fid*)
315 sendp(x->c, xfidflush);
321 filsysattach(Filsys *, Xfid *x, Fid *f)
325 if(strcmp(x->uname, x->fs->user) != 0)
326 return filsysrespond(x->fs, x, &t, Eperm);
334 sendp(x->c, xfidattach);
352 /* don't serve these if it's provided in the environment */
353 if(snarffd>=0 && strcmp(name, "snarf")==0)
355 if(gotscreen && strcmp(name, "screen")==0)
362 filsyswalk(Filsys *fs, Xfid *x, Fid *f)
375 return filsysrespond(fs, x, &t, "walk of open file");
377 if(x->fid != x->newfid){
378 /* BUG: check exists */
379 nf = newfid(fs, x->newfid);
381 return filsysrespond(fs, x, &t, "clone to busy fid");
388 nf->nrpart = 0; /* not open, so must be zero */
395 /* update f->qid, f->dir only if walk completes */
400 for(i=0; i<x->nwname; i++){
401 if((qid.type & QTDIR) == 0){
405 if(strcmp(x->wname[i], "..") == 0){
409 if(FILE(qid) == Qwsysdir)
414 err = "name too long";
419 qid.path = QID(id, path);
420 t.wqid[t.nwqid++] = qid;
424 if(qid.path == Qwsys){
425 /* is it a numeric name? */
426 if(!numeric(x->wname[i]))
428 /* yes: it's a directory */
429 id = atoi(x->wname[i]);
440 sendp(winclosechan, f->w);
445 if(skipdir(x->wname[i]))
451 if(strcmp(x->wname[i], d->name) == 0){
458 break; /* file not found */
465 if(err!=nil || t.nwqid<x->nwname){
468 sendp(winclosechan, nf->w);
472 }else if(t.nwqid == x->nwname){
477 return filsysrespond(fs, x, &t, err);
482 filsysopen(Filsys *fs, Xfid *x, Fid *f)
487 /* can't truncate anything, so just disregard */
488 x->mode &= ~(OTRUNC|OCEXEC);
489 /* can't execute or remove anything */
490 if(x->mode==OEXEC || (x->mode&ORCLOSE))
505 if(((f->dir->perm&~(DMDIR|DMAPPEND))&m) != m)
508 sendp(x->c, xfidopen);
512 return filsysrespond(fs, x, &t, Eperm);
517 filsyscreate(Filsys *fs, Xfid *x, Fid*)
521 return filsysrespond(fs, x, &t, Eperm);
526 idcmp(void *a, void *b)
528 return *(int*)a - *(int*)b;
533 filsysread(Filsys *fs, Xfid *x, Fid *f)
537 int i, n, o, e, len, j, k, *ids;
542 if((f->qid.type & QTDIR) == 0){
543 sendp(x->c, xfidread);
547 e = x->offset+x->count;
549 b = malloc(messagesize-IOHDRSZ); /* avoid memset of emalloc */
551 return filsysrespond(fs, x, &t, "out of memory");
553 switch(FILE(f->qid)){
557 d++; /* first entry is '.' */
558 for(i=0; d->name!=nil && i<e; d++){
561 len = dostat(fs, WIN(x->f->qid), d, b+n, x->count-n, clock);
571 ids = emalloc(nwindow*sizeof(int));
572 for(j=0; j<nwindow; j++)
573 ids[j] = window[j]->id;
575 qsort(ids, nwindow, sizeof ids[0], idcmp);
577 for(i=0, j=0; j<nwindow && i<e; i+=len){
579 sprint(dt.name, "%d", k);
580 dt.qid = QID(k, Qdir);
582 dt.perm = DMDIR|0700;
583 len = dostat(fs, k, &dt, b+n, x->count-n, clock);
595 filsysrespond(fs, x, &t, nil);
602 filsyswrite(Filsys*, Xfid *x, Fid*)
604 sendp(x->c, xfidwrite);
610 filsysclunk(Filsys *fs, Xfid *x, Fid *f)
617 sendp(x->c, xfidclose);
621 sendp(winclosechan, f->w);
624 return filsysrespond(fs, x, &t, nil);
629 filsysremove(Filsys *fs, Xfid *x, Fid*)
633 return filsysrespond(fs, x, &t, Eperm);
638 filsysstat(Filsys *fs, Xfid *x, Fid *f)
642 t.stat = emalloc(messagesize-IOHDRSZ);
643 t.nstat = dostat(fs, WIN(x->f->qid), f->dir, t.stat, messagesize-IOHDRSZ, getclock());
644 x = filsysrespond(fs, x, &t, nil);
651 filsyswstat(Filsys *fs, Xfid *x, Fid*)
655 return filsysrespond(fs, x, &t, Eperm);
660 newfid(Filsys *fs, int fid)
665 fh = &fs->fids[fid&(Nhash-1)];
666 for(f=*fh; f; f=f->next)
669 else if(ff==nil && f->busy==FALSE)
675 f = emalloc(sizeof *f);
689 read(clockfd, buf, sizeof buf);
695 dostat(Filsys *fs, int id, Dirtab *dir, uchar *buf, int nbuf, uint clock)
699 d.qid.path = QID(id, dir->qid);
700 if(dir->qid == Qsnarf)
701 d.qid.vers = snarfversion;
704 d.qid.type = dir->type;
706 d.length = 0; /* would be nice to do better */
713 return convD2M(&d, buf, nbuf);