ref: 16e9e2ac9e1fce7ac68b4401ed39893f74f13516
parent: 6597dea23c86fb467f951d4a9ec77ab248abfb68
author: Michael Misch <michaelmisch1985@gmail.com>
date: Sun Jun 9 04:23:03 EDT 2024
reverting to 9p.h
--- a/fs.c
+++ b/fs.c
@@ -2,9 +2,13 @@
#include <libc.h>
#include <ctype.h>
#include <fcall.h>
+#include <thread.h>
+#include <9p.h>
#include "alt.h"
+// TODO: Start turning off output if we aren't connected to anything
+
enum {Qroot,
Qclone,
@@ -25,392 +29,500 @@
Qmax,
};
-static char *qinfo[Qmax] = {- [Qroot] "/",
- [Qclone] "clone",
- [Qclients] nil,
- [Qctl] "ctl",
- [Qtitle] "title",
- [Qstatus] "status",
- [Qfeed] "feed",
- [Qaside] "aside",
- [Qnotify] "notify",
- [Qtabs] "tabs",
- [Qinput] "input",
- [Qservices] "services",
- [Qsclone] "clone",
- [Qservice] nil,
- [Qsctl] "ctl",
- [Qsinput] "input",
+static char *nametab[] = {+ "/",
+ "clone",
+ nil,
+ "ctl",
+ "title",
+ "status",
+ "feed",
+ "aside",
+ "notify",
+ "tabs",
+ "input",
+ "services",
+ "clone",
+ nil,
+ "ctl",
+ "input",
+ nil,
};
-typedef struct Fid Fid;
-struct Fid
+typedef struct Altfid Altfid;
+struct Altfid
{- int fid;
- ulong qtype;
- ulong uniq;
- int busy;
+ int level;
Client *client;
Service *service;
+ int fd;
vlong foffset;
- Fid *next;
};
-static char *whitespace = "\t\r\n";
-static int chatty9p = 0;
-static Fid *fids;
-static Fcall rhdr, thdr;
-static uchar mdata[8192 + IOHDRSZ];
-static int messagesize = sizeof mdata;
+static char *whitespace = "\t\r\n";
+void*
+emalloc(int n)
+{+ void *v;
+ v = emalloc9p(n);
+ setmalloctag(v, getcallerpc(&n));
+ memset(v, 0, n);
+ return v;
+}
-static void io(int, int);
-static Qid mkqid(Fid*);
-static Fid *findfid(int);
-static int dostat(Fid*, void*, int);
+char*
+estrdup(char *s)
+{+ s = estrdup9p(s);
+ setmalloctag(s, getcallerpc(&s));
+ return s;
+}
-static char *Auth(Fid*), *Attach(Fid*), *Version(Fid*),
- *Flush(Fid*), *Walk(Fid*), *Open(Fid*),
- *Create(Fid*), *Read(Fid*), *Write(Fid*),
- *Clunk(Fid*), *Remove(Fid*), *Stat(Fid*),
- *Wstat(Fid*);
+static void*
+wfaux(Altfid *f)
+{+ if(f->level < Qclients)
+ return nil;
+ else if(f->level < Qservices)
+ return f->client;
+ return f->service;
+}
-static char *(*fcalls[])(Fid*) = {- [Tattach] Attach,
- [Tauth] Auth,
- [Tclunk] Clunk,
- [Tflush] Flush,
- [Topen] Open,
- [Tread] Read,
- [Tremove] Remove,
- [Tstat] Stat,
- [Tversion] Version,
- [Twalk] Walk,
- [Twrite] Write,
- [Twstat] Wstat,
-};
-
-static char *
-Flush(Fid *f)
+static void
+fsmkqid(Qid *q, int level, void *aux)
{- USED(f);
- return 0;
+
+ q->type = 0;
+ q->vers = 0;
+ switch(level){+ case Qroot:
+ case Qclients:
+ case Qservices:
+ case Qservice:
+ q->type = QTDIR;
+ default:
+ q->path = (level<<24) | (((uintptr)aux ^ time0) & 0x00ffffff);
+ }
}
-static char *
-Auth(Fid *f)
+static void
+fsmkdir(Dir *d, int level, void *aux)
{- // TODO: Implement auth
- USED(f);
- return "alt/fs: authentication not required";
+ Service *sv;
+ char buf[1024];
+
+ memset(d, 0, sizeof(*d));
+ fsmkqid(&d->qid, level, aux);
+ d->mode = 0444;
+ d->atime = d->mtime = time0;
+ d->uid = estrdup(user);
+ d->gid = estrdup(user);
+ d->muid = estrdup(user);
+ if(d->qid.type & QTDIR)
+ d->mode |= DMDIR | 0111;
+ switch(level){+ case Qclients:
+ snprint(buf, sizeof(buf), "%d", CLIENTID(aux));
+ d->name = estrdup(buf);
+ break;
+ case Qservice:
+ sv = (Service*)aux;
+ d->name = sv->name;
+ break;
+ case Qctl:
+ case Qsctl:
+ case Qclone:
+ case Qsclone:
+ d->mode = 0666;
+ if(0){+ case Qinput:
+ d->mode = 0222;
+ }
+ default:
+ d->name = estrdup(nametab[level]);
+ }
}
-static char *
-Attach(Fid *f)
+static void
+fsattach(Req *r)
{- if(f->busy)
- Clunk(f);
- f->client = nil;
- f->service = nil;
- f->qtype = Qroot;
- f->busy = 1;
- thdr.qid = mkqid(f);
- return 0;
+ Altfid *f;
+
+ if(r->ifcall.aname && r->ifcall.aname[0]){+ respond(r, "invalid attach specifier");
+ return;
+ }
+ f = emalloc(sizeof(*f));
+ f->level = Qroot;
+ fsmkqid(&r->fid->qid, f->level, wfaux(f));
+ r->ofcall.qid = r->fid->qid;
+ r->fid->aux = f;
+ respond(r, nil);
}
-static char *
-Version(Fid*)
+static void
+fsstat(Req *r)
{- Fid *f;
- for(f = fids; f; f = f->next)
- if(f->busy)
- Clunk(f);
- if(rhdr.msize < 256)
- return "message size too small";
- if(rhdr.msize > sizeof(mdata))
- thdr.msize = sizeof mdata;
- else
- thdr.msize = rhdr.msize;
- thdr.version = "9P2000";
- if(strncmp(rhdr.version, "9P", 2) != 0)
- thdr.version = "unknown";
- return 0;
+ Altfid *f;
+
+ f = r->fid->aux;
+ fsmkdir(&r->d, f->level, wfaux(f));
+ respond(r, nil);
}
static char*
-Walk(Fid *f)
+fswalk1(Fid *fid, char *name, Qid *qid)
{- char *name, *err;
- int i, j; //isclient, isservice
- Fid *nf;
- ulong qtype;
+ Altfid *f;
+ int i, j;
+ i = 0;
- if(!f->busy)
- return "walk of unused fid";
+ if(!(fid->qid.type&QTDIR))
+ return "walk in non-directory";
- nf = nil;
- qtype = f->qtype;
- if(rhdr.fid != rhdr.newfid){- nf = findfid(rhdr.newfid);
- if(nf->busy)
- return "fid in use";
- f = nf;
- }
- err = nil;
- i = 0;
- if(rhdr.nwname > 0){- // We want to state if we're in a client or a service here in state
- for(; i<rhdr.nwname; i++){- if(i >= MAXWELEM){- err = "too many elements in path";
- break;
+ f = fid->aux;
+ if(strcmp(name, "..")==0){+ switch(f->level){+ case Qroot:
+ break;
+ case Qclients:
+ freeclient(f->client);
+ f->client = nil;
+ break;
+ case Qservices:
+ f->level = Qroot;
+ break;
+ default:
+ if(f->level > Qservices)
+ f->level = Qservices;
+ else
+ f->level = Qclients;
+ }
+ } else if(strcmp(name, "services")==0){+ i = Qservices;
+ goto Out;
+ } else {+ if(nservice){+ for(j=0; j < nservice; j++){+ if(strcmp(name, service[j].name) == 0){+ f->service = &service[j];
+ i = Qservice;
+ break;
+ }
}
- name = rhdr.wname[i];
- switch(qtype){- case Qroot:
- if(strcmp(name, "..") == 0)
- goto Accept;
- // TODO: Check if we are at a client
- if(f->client == nil)
- goto Out;
- qtype = Qclients;
- Accept:
- thdr.wqid[i] = mkqid(f);
- break;
- case Qclients:
- if(strcmp(name, "..") == 0){- qtype = Qroot;
- f->client = nil;
- goto Accept;
+ } else {+ for(i = f->level+1; i < nelem(nametab); i++){+ if(nametab[i]){+ if(strcmp(name, nametab[i]) == 0)
+ goto Out;
+ // anything else?
}
- for(j = Qclients + 1; j < Qmax; j++)
- if(strcmp(name, qinfo[j]) == 0){- qtype = j;
- break;
+ if(i == Qclients){+ j = atoi(name);
+ if(j >= 0 && j < nclient){+ f->client = &client[j];
+ incref(f->client);
+ goto Out;
}
- if(j < Qmax)
- goto Accept;
- goto Out;
- //case Qservices:
- //case Qservice:
- default:
- err = "file is not a directory";
- goto Out;
+ }
}
}
- Out:
- if(i < rhdr.nwname && err == nil)
- err = "file not found";
+Out:
+ if(i >= nelem(nametab))
+ return "directory entry not found";
+ f->level = i;
}
-
- if(err != nil)
- return err;
- if(rhdr.fid != rhdr.newfid && i == rhdr.nwname){- nf->busy = 1;
- nf->qtype = qtype;
- nf->client = f->client;
- nf->service = f->service;
- //if(nf->client != nil)
- // incref(nf->client);
- } else if (nf == nil && rhdr.nwname > 0){- Clunk(f);
- f->busy = 1;
- f->qtype = qtype;
- //if(f->client != nil)
- // incref(f->client);
- }
- thdr.nwqid = i;
- return 0;
+ fsmkqid(qid, f->level, wfaux(f));
+ fid->qid = *qid;
+ return nil;
}
-static char *
-Clunk(Fid *f)
+static char*
+fsclone(Fid *oldfid, Fid *newfid)
{- f->busy = 0;
- //freeservice, freeclient
- f->service = nil;
- f->client = nil;
+ Altfid *f, *o;
+ o = oldfid->aux;
+ if(o == nil)
+ return "bad fid";
+ f = emalloc(sizeof(*f));
+ memmove(f, o, sizeof(*f));
+ if(f->client)
+ incref(f->client);
+ newfid->aux = f;
return nil;
}
-static char *
-Open(Fid *f)
+static void
+fsopen(Req *r)
{- int mode;
+ Altfid *f;
+ Client *cl;
+ Service *svc;
+ char buf[256];
- if(!f->busy)
- return "open of unused fid";
- mode = rhdr.mode;
-
- // TODO: clone and sclone and feed
- // with feed, set up the real fid
- // with clone + sclone, return Qctl and Qsctl after creating each
- // though we do want access to setting a name after initialization
- // we can do numbered and just reject any matching names
- thdr.qid = mkqid(f);
- thdr.iounit = messagesize - IOHDRSZ;
- return 0;
+ // Switch and create on clones, etc
+ f = r->fid->aux;
+ cl = f->client;
+ svc = f->service;
+ USED(svc);
+ switch(f->level){+ case Qclone:
+ if((cl = newclient()) == nil){+ respond(r, "no more clients");
+ return;
+ }
+ f->level = Qctl;
+ f->client = cl;
+ fsmkqid(&r->fid->qid, f->level, wfaux(f));
+ r->ofcall.qid = r->fid->qid;
+ break;
+ case Qsclone:
+ if((svc = newservice()) == nil){+ respond(r, "no more services");
+ }
+ f->level = Qsctl;
+ f->service = svc;
+ fsmkqid(&r->fid->qid, f->level, wfaux(f));
+ r->ofcall.qid = r->fid->qid;
+ break;
+ case Qfeed:
+ if(cl->current){+ snprint(buf, sizeof(buf), "%s/%s", logdir, cl->current->feed);
+ print("%s\n", buf);+ f->fd = open(buf, 0644);
+ f->foffset = 0;
+ }
+ }
+ respond(r, nil);
}
-static char *
-Create(Fid *f)
+static int
+rootgen(int i, Dir *d, void *)
{- USED(f);
- return "permission denied";
+ i += Qroot+1;
+ if(i < Qclients){+ fsmkdir(d, i, 0);
+ return 0;
+ }
+ i -= Qclients;
+ if(i < nclient){+ fsmkdir(d, Qclients, &client[i]);
+ return 0;
+ }
+ // Final entry is just our services dir
+ if(i == nclient){+ fsmkdir(d, Qservices, 0);
+ return 0;
+ }
+ return -1;
}
-static char *
-Read(Fid *f)
+static int
+servicesgen(int i, Dir *d, void *)
{- USED(f);
- // switch on qtype, do the right thing.
- // Qroot: we want clone, services, and [0..9] clients
- // Qclient: we want all of our named files, etc
- // Qservices: we want clone and named services
- // Qservice: we want input, data, etc
- return "Open";
+ i += Qservices + 1;
+ if(i < Qservice){+ fsmkdir(d, i, 0);
+ return 0;
+ }
+ i -= Qservices + 2;
+ if(i < nservice){+ fsmkdir(d, Qservice, &service[i]);
+ return 0;
+ }
+ return -1;
}
-static char *
-Write(Fid *f)
+static int
+clientgen(int i, Dir *d, void *aux)
{- USED(f);
- // switch on qtype, do the write thing.
- return "Chimken";
+ // TODO: Mask the unusable files if we have no current buffer
+ i += Qclients+1;
+ if(i > Qinput)
+ return -1;
+ fsmkdir(d, i, aux);
+ return 0;
}
-static char *
-Remove(Fid *f)
+static int
+servicegen(int i, Dir *d, void *aux)
{- Clunk(f);
- return "permission denied";
+ i += Qservice+1;
+print("%d %d\n", i, Qmax);+ if(i >= Qmax)
+ return -1;
+ fsmkdir(d, i, aux);
+ return 0;
}
-static char *
-Stat(Fid *f)
+static void
+fsread(Req *r)
{- static uchar statbuf[1024];
+ char buf[1024];
+ Altfid *f;
+ Client *cl;
+ Service *svc;
- if(!f->busy)
- return "stat on unused fd";
- thdr.nstat = dostat(f, statbuf, sizeof statbuf);
- if(thdr.nstat <= BIT16SZ)
- return "stat buffer too small";
- thdr.stat = statbuf;
- return 0;
-}
+ f = r->fid->aux;
+ cl = f->client;
+ svc = f->service;
+
+ if(f->level > Qctl && f->level < Qservices && !cl->current){+ respond(r, "no current buffer selected");
+ return;
+ }
-static char *
-Wstat(Fid *f)
-{- //Dir d;
- //int n;
- //char buf[1024];
- // TODO: Anything we want to allow here
- USED(f);
- return "permission denied";
+ switch(f->level){+ case Qroot:
+print("Root\n");+ dirread9p(r, rootgen, nil);
+ respond(r, nil);
+ return;
+ case Qclients:
+print("Clients\n");+ dirread9p(r, clientgen, nil);
+ respond(r, nil);
+ return;
+ case Qservices:
+print("Services\n");+ dirread9p(r, servicesgen, nil);
+ respond(r, nil);
+ return;
+ case Qservice:
+print("Service\n");+ dirread9p(r, servicegen, nil);
+ respond(r, nil);
+ return;
+ case Qtitle:
+ snprint(buf, sizeof(buf), "%s\n", cl->current->title);
+ String:
+ readstr(r, buf);
+ respond(r, nil);
+ return;
+ case Qctl:
+ snprint(buf, sizeof(buf), "%d\n", CLIENTID(f->client));
+ goto String;
+ case Qstatus:
+ snprint(buf, sizeof(buf), "%s\n", cl->current->status);
+ goto String;
+ case Qaside:
+ snprint(buf, sizeof(buf), "%s\n", cl->current->aside);
+ goto String;
+ case Qsctl:
+ snprint(buf, sizeof(buf), "%s\n", svc->name);
+ goto String;
+ case Qfeed:
+ pread(f->fd, buf, sizeof(buf), f->foffset);
+ goto String;
+ case Qsinput:
+ // forward any pending input from client
+ // TODO: Channel for input?
+ break;
+ case Qnotify:
+ // TODO: notify fmt %N, install at start
+ //snprint(buf, sizeof(buf), "%N\n", svc->notify);
+ break;
+ case Qtabs:
+ // TODO: tabs fmt %T, install at start
+ //snprint(buf, sizeof(buf), "%T\n", svc);
+ goto String;
+
+ }
+ respond(r, "not implemented");
}
-static Qid
-mkqid(Fid *f)
+static void
+fswrite(Req *r)
{- Qid q;
+ int n;
+ Altfid *f;
+ char *s, *t;
- q.vers = 0;
- q.path = f->qtype;
- if(f->service || f->client)
- q.path |= f->uniq * 0x100;
-
- switch(f->qtype){- case Qservice:
- case Qservices:
- case Qclients:
- case Qroot:
- q.type = QTDIR;
- default:
- q.type = QTFILE;
+ f = r->fid->aux;
+ switch(f->level){+ case Qsctl:
+ case Qctl:
+ n = r->ofcall.count = r->ifcall.count;
+ s = emalloc(n+1);
+ memmove(s, r->ifcall.data, n);
+ while(n > 0 && strchr("\r\n", s[n-1]))+ n--;
+ s[n] = 0;
+ // TODO: We don't use any of this in any meaningful way, remove t from calls
+ t = s;
+ while(*t && strchr(whitespace, *t)==0)
+ t++;
+ while(*t && strchr(whitespace, *t))
+ *t++ = 0;
+ if(f->level == Qctl)
+ t = clientctl(f->client, s, t);
+ else
+ t = servicectl(f->service, s, t);
+ free(s);
+ respond(r, t);
+ return;
+ case Qinput:
+ // TODO: User wrote a string to us, forward to server (cb?)
+ //f->svc->callback(r->ifcall.data, r->ifcall.count);
+ return;
}
- return q;
+ respond(r, "not implemented");
}
-static int
-dostat(Fid *f, void *p, int n)
+static void
+fsflush(Req *r)
{- Dir d;
-
- if(f->qtype == Qservice)
- d.name = f->service->name;
- // TODO: look up the n for the client if we're in client
- else
- d.name = qinfo[f->qtype];
- d.uid = d.gid = d.muid = "none";
- d.qid = mkqid(f);
- if(d.qid.type & QTDIR)
- d.mode = 0755|DMDIR;
- else
- d.mode = 0644;
- d.atime = d.mtime = time(0);
- d.length = 0;
- return convD2M(&d, p, n);
+ respond(r, nil);
}
-static Fid *
-findfid(int fid)
+static void
+fsdestroyfid(Fid *fid)
{- Fid *f, *ff;
+ Altfid *f;
- ff = nil;
- for(f = fids; f; f = f->next)
- if(f->fid == fid)
- return f;
- else if(!ff && !f->busy)
- ff = f;
- if(ff != nil){- ff->fid = fid;
- return ff;
- }
-
- f = emalloc(sizeof *f);
- f->fid = fid;
- f->busy = 0;
- f->client = nil;
- f->service = nil;
- f->next = fids;
- fids = f;
- return f;
+ if(f = fid->aux){+ fid->aux = nil;
+ if(f->client)
+ freeclient(f->client);
+ // TODO: uncomment so services hold open an FD to show their livelihood
+ //if(f->service)
+ // freeservice(f->service);
+ free(f);
+ }
}
static void
-io(int in, int out)
+fsstart(Srv*)
{- char *err;
- int n;
-
- while((n = read9pmsg(in, mdata, messagesize)) != 0){- if(n < 0)
- fprint(2, "mount read: %r");
- if(convM2S(mdata, n, &rhdr) != n)
- fprint(2, "convM2S format error: %r");
- thdr.data = (char*)mdata + IOHDRSZ;
- thdr.fid = rhdr.fid;
- if(!fcalls[rhdr.type])
- err = "bad fcall request";
- else
- err = (*fcalls[rhdr.type])(findfid(rhdr.fid));
- thdr.tag = rhdr.tag;
- thdr.type = rhdr.type + 1;
- if(err){- thdr.type = Rerror;
- thdr.ename = err;
- }
- n = convS2M(&thdr, mdata, messagesize);
- if(write(out, mdata, n) != n)
- fprint(2, "mount write\n");
- }
+ /* Overwrite if we have one, force a reconnect of everything */
+ if(mtpt != nil)
+ unmount(nil, mtpt);
}
static void
+fsend(Srv*)
+{+ postnote(PNGROUP, getpid(), "shutdown");
+ exits(nil);
+}
+
+Srv fs =
+{+ .start=fsstart,
+ .attach=fsattach,
+ .stat=fsstat,
+ .walk1=fswalk1,
+ .clone=fsclone,
+ .open=fsopen,
+ .read=fsread,
+ .write=fswrite,
+ .flush=fsflush,
+ .destroyfid=fsdestroyfid,
+ .end=fsend,
+};
+
+void
usage(void)
{fprint(2, "usage: %s [-Dd] [-m mtpt] [-s service] [-l logdir]\n", argv0);
@@ -422,11 +534,10 @@
{// We could use quotefmtinstall here
// add in tabs at very least
- int p[2];
-
user = getuser();
mtpt = "/mnt/alt";
logdir = "/tmp/alt";
+ time0 = time(0);
ARGBEGIN {case 'D':
@@ -450,48 +561,7 @@
argv0 = "alt/fs";
- if(pipe(p) < 0)
- sysfatal("Can't make pipe: %r");-
create(logdir, OREAD, DMDIR | 0755);
- switch(rfork(RFPROC|RFNAMEG|RFNOTEG|RFNOWAIT|RFENVG|RFFDG|RFMEM)){- case 0:
- close(p[0]);
- io(p[1], p[1]);
- postnote(PNPROC, 1, "shutdown");
- exits(0);
- case -1:
- sysfatal("fork");- default:
- close(p[1]);
- // TODO: We want to srv if we have srvpt
- if(mount(p[0], -1, mtpt, MREPL|MCREATE, "") == -1)
- sysfatal("can't mount: %r");- exits(0);
- }
+ postmountsrv(&fs, srvpt, mtpt, MCREATE);
+ exits(nil);
}
-
-void*
-emalloc(int n)
-{- void *p;
-
- if((p = malloc(n)) != nil){- memset(p, 0, n);
- return p;
- }
- sysfatal("out of memory");-}
-
-char*
-estrdup(char *s)
-{- char *d;
- int n;
-
- n = strlen(s)+1;
- d = emalloc(n);
- memmove(d, s, n);
- return d;
-}
-
--
⑨