ref: d41d7a57904b372d1be5521f07be41aacb200817
parent: 16e9e2ac9e1fce7ac68b4401ed39893f74f13516
author: Michael Misch <michaelmisch1985@gmail.com>
date: Tue Jun 11 09:36:00 EDT 2024
Use our alternative approach which ends up much cleaner, and avoids necessary namespace awkwardness
--- a/TODO
+++ b/TODO
@@ -1,18 +1,34 @@
-/mnt/altid/clone
-/mnt/altid/stats
-/mnt/altid/[0-9]
-/mnt/altid/[0-9]/feed
-/mnt/altid/[0-9]/...
+ Commands:
+ - markup, will need to import the state machine parser to pre-parse the output into just text
+ - tabs could be a command?
-/mnt/altid/service
-/mnt/altid/service/clone
-/mnt/altid/service/[0-9]
+Post a descriptor to /srv for each given service, that a client can connect into
+alt/fs sname, then in that namespace run the service binary
+It mounts to /mnt/alt, which is what the service reads and writes to, then the client will do the other side
-Can read stats for list of servers, etc
-Clone, get your n back
-/mnt/altid/1/ctl, write which service to connect to
-the fs populates with that, you can read in tabs to see what buffers are available
+if(isInitial) could be set to true on spinup, then we attach and flag appropriately; then negate isInitial so we can always assume a client attach after
-Commands:
- - markup, will need to import the state machine parser to pre-parse the output into just text
- - tabs could be a command?
\ No newline at end of file
+ - Do a Srv + postmountsrv in main, then Srv + postsrv or listensrv in client.c which is fired off after attach from a service and initialization is complete
+Client
+
+```
+#!/bin/rc
+
+# Example /bin/rc/service/tcp18111
+mount '#s/libera' /mnt/irc
+exec /bin/exportfs -r /mnt/irc
+```
+
+Connects with aname = desired buffer, or gets just whichever is first (usually a `server`, but just in added-order)
+ - if no buffers exist, exit error. We don't support hung states!
+
+Service
+
+`/mnt/alt` is served by the alt/fs
+- service will write the service name to `/mnt/alt/clone`
+ - If a service exists in /srv by that name, an error will be returned. rm the service first!
+ - If the name is not valid filechars, an error will be returned (this is used in /srv, after all)
+- the service reads and writes to the returned fd until it closes, signalling completion
+
+
+Add a stats/info file to /mnt/alt? something anyways.
--- a/alt.h
+++ b/alt.h
@@ -1,16 +1,15 @@
-#define CLIENTID(c) ((int)(((Client*)(c)) - client))
-
typedef struct Buffer Buffer;
typedef struct Notify Notify;
-typedef struct Service Service;
-typedef struct Client Client;
struct Buffer
{char title[256];
char status[256];
- char feed[256];
char *aside;
+ int fd;
+ Notify *notify;
+ // callback function from server for processing input
+ Buffer *next;
};
struct Notify
@@ -19,28 +18,6 @@
Notify *next;
};
-struct Service
-{- Buffer *buffer;
- Notify *notifications;
- //input callback function here
- char *name;
- Service *next;
-};
-
-struct Client
-{- Buffer *current;
- int showmarkdown;
- int ref;
-};
-
-Client* newclient(void);
-void freeclient(Client*);
-char* clientctl(Client*, char*, char*);
-Service* newservice(void);
-void freeservice(Service*);
-char* servicectl(Service*, char*, char*);
void* emalloc(int);
char* estrdup(char*);
@@ -47,10 +24,29 @@
char *mtpt;
char *srvpt;
char *user;
-long time0;
char *logdir;
-Client client[256];
-int nclient;
-Service service[64];
-int nservice;
int debug;
+
+void clattach(Req*);
+void clstat(Req*);
+char *clwalk1(Fid*, char*, Qid*);
+char *clclone(Fid*, Fid*);
+void clopen(Req*);
+void clread(Req*);
+void clwrite(Req*);
+void clflush(Req*);
+void cldestroyfid(Fid*);
+void clstart(Srv*);
+void clend(Srv*);
+
+void svcattach(Req*);
+void svcstat(Req*);
+char *svcwalk1(Fid*, char*, Qid*);
+char *svcclone(Fid*, Fid*);
+void svcopen(Req*);
+void svcread(Req*);
+void svcwrite(Req*);
+void svcflush(Req*);
+void svcdestroyfid(Fid*);
+void svcstart(Srv*);
+void svcend(Srv*);
--- a/client.c
+++ b/client.c
@@ -6,7 +6,53 @@
#include "alt.h"
-Client*
+enum {+ Qcroot,
+ Qtitle,
+ Qstatus,
+ Qaside,
+ Qfeed,
+ Qinput,
+ Qnotify,
+ Qctl,
+ Qmax,
+};
+
+static char *cltab[] = {+ "/",
+ "title",
+ "status",
+ "aside",
+ "feed",
+ "input",
+ "notify",
+ "ctl",
+ nil,
+};
+
+typedef struct Clfid Clfid;
+typedef struct Client Client;
+
+struct Clfid
+{+ int level;
+ Client *cl;
+};
+
+struct Client
+{+ Ref;
+
+ Buffer *current;
+ int showmarkdown;
+};
+
+static Client client[256];
+static Buffer *root;
+static int nclient;
+static int time0;
+
+static Client*
newclient(void)
{Client *cl;
@@ -28,7 +74,7 @@
return cl;
}
-void
+static void
freeclient(Client *cl)
{if(cl == nil || cl->ref == 0)
@@ -40,16 +86,180 @@
memset(cl, 0, sizeof(*cl));
}
+static void
+clmkqid(Qid *q, int level, void *aux)
+{+ q->type = 0;
+ q->vers = 0;
+ if(level == Qcroot)
+ q->type = QTDIR;
+ else
+ q->path = (level<<24) | (((uintptr)aux ^ time0) & 0x00ffffff);
+}
+
+static void
+clmkdir(Dir *d, int level, void *aux)
+{+ memset(d, 0, sizeof(*d));
+ clmkqid(&d->qid, level, aux);
+ d->mode = 0444;
+ d->atime = d->mtime = time(0);
+ d->uid = estrdup(user);
+ d->gid = estrdup(user);
+ d->muid = estrdup(user);
+ if(d->qid.type & QTDIR)
+ d->mode |= DMDIR | 0111;
+ switch(level){+ case Qctl:
+ d->mode = 0666;
+ default:
+ d->name = estrdup(cltab[level]);
+ }
+}
+
+void
+clattach(Req *r)
+{+ Clfid *f;
+
+ // TODO: We want to actually use the aname here
+ if(r->ifcall.aname && r->ifcall.aname[0]){+ print(r->ifcall.aname);
+ // TODO: Check and establish buffer, abort if it's not available
+ } else {+ // TODO: If we have any valid buffers, we take the top of the list here
+ }
+ f = emalloc(sizeof(*f));
+ f->level = Qcroot;
+ clmkqid(&r->fid->qid, f->level, nil);
+ r->ofcall.qid = r->fid->qid;
+ r->fid->aux = f;
+ respond(r, nil);
+}
+
+
+
+void
+clstat(Req *r)
+{+ Clfid *f;
+
+ f = r->fid->aux;
+ clmkdir(&r->d, f->level, f->cl);
+ respond(r, nil);
+}
+
+
char*
-clientctl(Client *cl, char *ctl, char *arg)
+clwalk1(Fid *fid, char *name, Qid *qid)
{- USED(cl);
- print("Command in: %s\nArgs in: %s\n", ctl, arg);- if(strcmp(ctl, "buffer") == 0){+ Clfid *f;
+ int i;
- } else{- // Clients should be polling for commands and input alike
-
+ if(!(fid->qid.type&QTDIR))
+ return "walk in non-directory";
+
+ f = fid->aux;
+ for(i=f->level+1; i < nelem(cltab); i++){+ if(cltab[i]){+ if(strcmp(name, cltab[i]) == 0)
+ break;
+ }
}
+ if(i >= nelem(cltab))
+ return "directory entry not found";
+ f->level = i;
+ clmkqid(qid, f->level, f->cl);
+ fid->qid = *qid;
+ return nil;
+}
+
+char *
+clclone(Fid *oldfid, Fid *newfid)
+{+ Clfid *f, *o;
+
+ o = oldfid->aux;
+ if(o == nil)
+ return "bad fid";
+ f = emalloc(sizeof(*f));
+ memmove(f, o, sizeof(*f));
+ if(f->cl)
+ incref(f->cl);
+ newfid->aux = f;
return nil;
+}
+
+void
+clopen(Req *r)
+{+ respond(r, nil);
+ // Use feed for fid, with offset as well.
+}
+
+static int
+rootgen(int i, Dir *d, void *aux)
+{+ i += Qcroot+1;
+ if(i < Qmax){+ clmkdir(d, i, aux);
+ return 0;
+ }
+ return -1;
+}
+
+void
+clread(Req *r)
+{+ Clfid *f;
+
+ f = r->fid->aux;
+ switch(f->level){+ case Qcroot:
+ dirread9p(r, rootgen, f->cl);
+ respond(r, nil);
+ return;
+ //case Qfeed:
+ }
+ respond(r, "not implemented");
+}
+
+void
+clwrite(Req *r)
+{+ // TODO: Input, ctl
+ respond(r, nil);
+}
+
+void
+clflush(Req *r)
+{+ respond(r, nil);
+}
+
+void
+cldestroyfid(Fid *fid)
+{+ Clfid *f;
+
+ if(f = fid->aux){+ //fid->aux = nil;
+ //if(f->cl)
+ // freeclient(f->cl);
+ }
+ free(f);
+}
+
+void
+clstart(Srv *s)
+{+ root = (Buffer*)s->aux;
+ time0 = time(0);
+}
+
+void
+clend(Srv*)
+{+ postnote(PNGROUP, getpid(), "shutdown");
+ exits(nil);
}
--- a/fs.c
+++ b/fs.c
@@ -7,60 +7,6 @@
#include "alt.h"
-// TODO: Start turning off output if we aren't connected to anything
-
-enum {- Qroot,
- Qclone,
- Qclients,
- Qctl,
- Qtitle,
- Qstatus,
- Qfeed,
- Qaside,
- Qnotify,
- Qtabs,
- Qinput,
- Qservices,
- Qsclone,
- Qservice,
- Qsctl,
- Qsinput,
- Qmax,
-};
-
-static char *nametab[] = {- "/",
- "clone",
- nil,
- "ctl",
- "title",
- "status",
- "feed",
- "aside",
- "notify",
- "tabs",
- "input",
- "services",
- "clone",
- nil,
- "ctl",
- "input",
- nil,
-};
-
-typedef struct Altfid Altfid;
-struct Altfid
-{- int level;
- Client *client;
- Service *service;
- int fd;
- vlong foffset;
-};
-
-static char *whitespace = "\t\r\n";
-
void*
emalloc(int n)
{@@ -79,447 +25,19 @@
return s;
}
-static void*
-wfaux(Altfid *f)
+Srv svcfs =
{- if(f->level < Qclients)
- return nil;
- else if(f->level < Qservices)
- return f->client;
- return f->service;
-}
-
-static void
-fsmkqid(Qid *q, int level, void *aux)
-{-
- 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 void
-fsmkdir(Dir *d, int level, void *aux)
-{- 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 void
-fsattach(Req *r)
-{- 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 void
-fsstat(Req *r)
-{- Altfid *f;
-
- f = r->fid->aux;
- fsmkdir(&r->d, f->level, wfaux(f));
- respond(r, nil);
-}
-
-static char*
-fswalk1(Fid *fid, char *name, Qid *qid)
-{- Altfid *f;
- int i, j;
- i = 0;
-
- if(!(fid->qid.type&QTDIR))
- return "walk in non-directory";
-
- 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;
- }
- }
- } else {- for(i = f->level+1; i < nelem(nametab); i++){- if(nametab[i]){- if(strcmp(name, nametab[i]) == 0)
- goto Out;
- // anything else?
- }
- if(i == Qclients){- j = atoi(name);
- if(j >= 0 && j < nclient){- f->client = &client[j];
- incref(f->client);
- goto Out;
- }
- }
- }
- }
-Out:
- if(i >= nelem(nametab))
- return "directory entry not found";
- f->level = i;
- }
- fsmkqid(qid, f->level, wfaux(f));
- fid->qid = *qid;
- return nil;
-}
-
-static char*
-fsclone(Fid *oldfid, Fid *newfid)
-{- 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 void
-fsopen(Req *r)
-{- Altfid *f;
- Client *cl;
- Service *svc;
- char buf[256];
-
- // 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 int
-rootgen(int i, Dir *d, void *)
-{- 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 int
-servicesgen(int i, Dir *d, void *)
-{- 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 int
-clientgen(int i, Dir *d, void *aux)
-{- // 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 int
-servicegen(int i, Dir *d, void *aux)
-{- i += Qservice+1;
-print("%d %d\n", i, Qmax);- if(i >= Qmax)
- return -1;
- fsmkdir(d, i, aux);
- return 0;
-}
-
-static void
-fsread(Req *r)
-{- char buf[1024];
- Altfid *f;
- Client *cl;
- Service *svc;
-
- 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;
- }
-
- 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 void
-fswrite(Req *r)
-{- int n;
- Altfid *f;
- char *s, *t;
-
- 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;
- }
- respond(r, "not implemented");
-}
-
-static void
-fsflush(Req *r)
-{- respond(r, nil);
-}
-
-static void
-fsdestroyfid(Fid *fid)
-{- Altfid *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
-fsstart(Srv*)
-{- /* 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,
+ .start=svcstart,
+ .attach=svcattach,
+ .stat=svcstat,
+ .walk1=svcwalk1,
+ .clone=svcclone,
+ .open=svcopen,
+ .read=svcread,
+ .write=svcwrite,
+ .flush=svcflush,
+ .destroyfid=svcdestroyfid,
+ .end=svcend,
};
void
@@ -530,7 +48,7 @@
}
void
-main(int argc, char *argv[])
+threadmain(int argc, char *argv[])
{// We could use quotefmtinstall here
// add in tabs at very least
@@ -537,7 +55,6 @@
user = getuser();
mtpt = "/mnt/alt";
logdir = "/tmp/alt";
- time0 = time(0);
ARGBEGIN {case 'D':
@@ -546,9 +63,6 @@
case 'm':
mtpt = EARGF(usage());
break;
- case 's':
- srvpt = EARGF(usage());
- break;
case 'l':
logdir = EARGF(usage());
break;
@@ -562,6 +76,6 @@
argv0 = "alt/fs";
create(logdir, OREAD, DMDIR | 0755);
- postmountsrv(&fs, srvpt, mtpt, MCREATE);
+ threadpostmountsrv(&svcfs, nil, mtpt, MCREATE);
exits(nil);
}
--- a/service.c
+++ b/service.c
@@ -6,24 +6,85 @@
#include "alt.h"
-Service*
+#define SERVICEID(c) ((int)(((Service*)(c)) - service))
+
+enum {+ Qsroot,
+ Qclone,
+ Qservices,
+ Qctl,
+ Qmax,
+};
+
+static char *svctab[] = {+ "/",
+ "clone",
+ nil,
+ "ctl",
+ nil,
+};
+
+Srv clfs =
+{+ .start=clstart,
+ .attach=clattach,
+ .stat=clstat,
+ .walk1=clwalk1,
+ .clone=clclone,
+ .open=clopen,
+ .read=clread,
+ .write=clwrite,
+ .flush=clflush,
+ .destroyfid=cldestroyfid,
+ .end=clend,
+};
+
+typedef struct Svcfid Svcfid;
+typedef struct Service Service;
+
+struct Svcfid
+{ int level;+ Service *svc;
+ // Who knows
+};
+
+struct Service
+{+ Ref;
+
+ Buffer *base;
+ char *name;
+ int isInitialized;
+ int childpid;
+};
+
+Service service[64];
+int nservice;
+
+static Service*
newservice(void)
{- Service *sv;
- char buf[1024];
-
- sv = &service[nservice];
- nservice++;
+ Service *svc;
+ int i;
- sv->buffer = nil;
- sv->notifications = nil;
- snprint(buf, sizeof(buf), "default");
- sv->name = estrdup(buf);
+ for(i = 0; i < nservice; i++)
+ if(service[i].ref == 0)
+ break;
+ if(i >= nelem(service))
+ return nil;
+ if(i == nservice)
+ nservice++;
+ svc = &service[i];
+ svc->ref++;
+
+ // TODO: Instantiate a proper base
+ svc->base = nil;
+ svc->isInitialized = 0;
- return sv;
+ return svc;
}
-void
+static void
freeservice(Service *s)
{if(s == nil)
@@ -31,14 +92,283 @@
memset(s, 0, sizeof(*s));
}
+static void*
+wfaux(Svcfid *f)
+{+ if(f->level < Qservices)
+ return nil;
+ return f->svc;
+}
+
+static void
+svcmkqid(Qid *q, int level, void *)
+{+ q->type = 0;
+ q->vers = 0;
+ switch(level){+ case Qsroot:
+ case Qservices:
+ q->type = QTDIR;
+ default:
+ ;
+ }
+}
+
+static void
+svcmkdir(Dir *d, int level, void *aux)
+{+ char buf[1024];
+
+ memset(d, 0, sizeof(*d));
+ svcmkqid(&d->qid, level, aux);
+ d->mode = 0444;
+ d->atime = d->mtime = time(0);
+ d->uid = estrdup(user);
+ d->gid = estrdup(user);
+ d->muid = estrdup(user);
+ if(d->qid.type & QTDIR)
+ d->mode |= DMDIR | 0111;
+ switch(level){+ case Qservices:
+ snprint(buf, sizeof(buf), "%d", SERVICEID(aux));
+ d->name = estrdup(buf);
+ break;
+ case Qctl:
+ case Qclone:
+ d->mode = 0666;
+ default:
+ d->name = estrdup(svctab[level]);
+ }
+}
+
+void
+svcattach(Req *r)
+{+ Svcfid *f;
+
+ // No anames
+ if(r->ifcall.aname && r->ifcall.aname[0]){+ respond(r, "invalid attach specifier");
+ return;
+ }
+ f = emalloc(sizeof(*f));
+ f->level = Qsroot;
+ svcmkqid(&r->fid->qid, f->level, wfaux(f));
+ r->ofcall.qid = r->fid->qid;
+ r->fid->aux = f;
+ respond(r, nil);
+}
+
+void
+svcstat(Req *r)
+{+ Svcfid *f;
+
+ f = r->fid->aux;
+ svcmkdir(&r->d, f->level, wfaux(f));
+ respond(r, nil);
+}
+
char*
-servicectl(Service *svc, char *ctl, char *arg)
+svcwalk1(Fid *fid, char *name, Qid *qid)
{- char *target, *buffer;
- USED(svc, ctl, arg);
- //ctl is like title:##meskarune
- target = strstr(":", ctl);- buffer = strstr(nil, ctl);
- print("%s and %s\n", buffer, target);+ Svcfid *f;
+ int i, j;
+
+ if(!(fid->qid.type&QTDIR))
+ return "walk in non-directory";
+
+ f = fid->aux;
+ if(strcmp(name, "..")==0){+ switch(f->level){+ case Qsroot:
+ break;
+ case Qservices:
+ f->level = Qsroot;
+ break;
+ default:
+ f->level = Qservices;
+ }
+ } else {+ for(i = f->level+1; i < nelem(svctab); i++){+ if(svctab[i])
+ if(strcmp(name, svctab[i]) == 0)
+ goto Out;
+ if(i == Qservices){+ j = atoi(name);
+ if(j >= 0 && j < nservice){+ f->svc = &service[j];
+ incref(f->svc);
+ goto Out;
+ }
+ }
+ }
+Out:
+ if(i >= nelem(svctab))
+ return "directory entry not found";
+ f->level = i;
+ }
+ svcmkqid(qid, f->level, wfaux(f));
+ fid->qid = *qid;
return nil;
+}
+
+char *
+svcclone(Fid *oldfid, Fid *newfid)
+{+ Svcfid *f, *o;
+ o = oldfid->aux;
+ if(o == nil)
+ return "bad fid";
+ f = emalloc(sizeof(*f));
+ memmove(f, o, sizeof(*f));
+ if(f->svc)
+ incref(f->svc);
+ newfid->aux = f;
+ return nil;
+}
+
+void
+svcopen(Req *r)
+{+ Svcfid *f;
+ Service *svc;
+
+ f = r->fid->aux;
+ if(f->level == Qclone){+ if((svc = newservice()) == nil){+ respond(r, "no more services");
+ return;
+ }
+ f->level = Qctl;
+ f->svc = svc;
+ svcmkqid(&r->fid->qid, f->level, wfaux(f));
+ r->ofcall.qid = r->fid->qid;
+ }
+ respond(r, nil);
+}
+
+static int
+rootgen(int i, Dir *d, void *)
+{+ i += Qsroot+1;
+ if(i < Qservices){+ svcmkdir(d, i, 0);
+ return 0;
+ }
+ i -= Qservices;
+ if(i < nservice){+ svcmkdir(d, Qservices, &service[i]);
+ return 0;
+ }
+ return -1;
+}
+
+static int
+servicegen(int i, Dir *d, void *aux)
+{+ i += Qservices+1;
+ if(i >= Qmax)
+ return -1;
+ svcmkdir(d, i, aux);
+ return 0;
+}
+
+void
+svcread(Req *r)
+{+ char buf[1024];
+ Svcfid *f;
+
+ f = r->fid->aux;
+
+ switch(f->level){+ case Qsroot:
+ dirread9p(r, rootgen, nil);
+ respond(r, nil);
+ return;
+ case Qservices:
+ dirread9p(r, servicegen, nil);
+ respond(r, nil);
+ return;
+ case Qctl:
+ snprint(buf, sizeof(buf), "%d\n", SERVICEID(f->svc));
+ readstr(r, buf);
+ respond(r, nil);
+ return;
+ }
+ respond(r, "not implemented");
+}
+
+void
+svcwrite(Req *r)
+{+ int n;
+ char *s;
+ Svcfid *f;
+
+ f = r->fid->aux;
+
+ if(f->level == Qctl){+ n = r->ofcall.count = r->ifcall.count;
+ s = emalloc(n+1);
+ memmove(s, r->ifcall.data, n);
+ s[n] = 0;
+ if(n > 0 && s[n-1] == '\n')
+ s[n-1] = 0;
+ if(f->svc->isInitialized){+ print("Command: %s\n", s);+
+ respond(r, nil);
+ } else {+ f->svc->name = estrdup(s);
+ // TODO: Buffers will have an input cb from the server
+ clfs.aux = f->svc->base;
+ f->svc->childpid = threadpostsrv(&clfs, s);
+ if(f->svc->childpid >= 0){+ f->svc->isInitialized++;
+ respond(r, nil);
+ } else
+ respond(r, "Unable to post to srv");
+ }
+ free(s);
+ return;
+ }
+ respond(r, "not implemented");
+}
+
+void
+svcflush(Req *r)
+{+ respond(r, nil);
+}
+
+void
+svcdestroyfid(Fid *fid)
+{+ Svcfid *f;
+
+ if(f = fid->aux){+ //if(f->svc && f->svc->childpid)
+ // postnote(PNGROUP, f->svc->childpid, "shutdown");
+ // TODO: Uncomment this after we are good to go, this is our keepalive roughly
+ //fid->aux = nil;
+ //if(f->svc)
+ // freeservice(f->svc);
+ }
+ free(f);
+}
+
+void
+svcstart(Srv*)
+{+ if(mtpt != nil)
+ unmount(nil, mtpt);
+}
+
+void
+svcend(Srv*)
+{+ postnote(PNGROUP, getpid(), "shutdown");
+ threadexitsall(nil);
}
--
⑨