From: Michael Misch <michaelmisch1985@gmail.com>
To: 9front@9front.org
Subject: ndb/registry
Date: Fri, 28 Aug 2020 21:17:40 -0700 [thread overview]
Message-ID: <324735A7-38EE-4288-87B3-765667AEF962@gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 1650 bytes --]
Hey, I’ve been working this last week on bringing ndb/registry over from inferno, but in a way that matches well with the rest of our ndb.
I have two binaries, ndb/registry and ndb/regquery. ndb/registry reads from /lib/ndb/registry, which would contain a list of local services you want to register on start up. They’re in regular ndb format, and look like
service=tcp!myipaddr!1234
auth=none label=myservice
mtpt=/n/myservice
You can add a service by writing, `add tcp!myipaddr!1234 label myservice [mtpt mymtpt label mylabel]` to /net/registry, rm `rm tcp!myipaddr!1234`, edit, `update tcp!myipaddr!1234 label newlabel` or any other tuple. Dump will create a dump of the current registry to /lib/ndb/regdump, refresh will reload the services from the db - while keeping any that you’ve added after startup untouched.
regquery opens and reads /net/registry, and outputs any matching service descriptions `ndb/regquery myservice`, in tuple format; or as a plumbable string (currently only srv and srvtls) with -s, and will list all services when passed `ndb/regquery all`.
eg:
ndb/regquery grid
service=tcp!myservice!1234 label=gridchat auth=none mtpt=/n/chat
[ … ] // any other matches
ndb/regquery -s grid
srv tcp!myservice!1234 gridchat /n/chat
[ … ] // any other matches
I use this with a database containing, at the moment the 9grid list of services, but would be useful for a general index of what services exist on a given network outright, on a remote network for bookkeeping, etc.
The code is fresh, and may have bugs I haven’t caught! I’ll include the diff here, thanks!
- halfwit
[-- Attachment #2: ndb.patch --]
[-- Type: application/octet-stream, Size: 24478 bytes --]
diff -r 8127893f53b1 sys/src/cmd/ndb/dns.h
--- a/sys/src/cmd/ndb/dns.h Wed Aug 26 21:17:17 2020 -0700
+++ b/sys/src/cmd/ndb/dns.h Fri Aug 28 20:55:56 2020 -0700
@@ -143,6 +143,9 @@
Maxpath= 128, /* size of mntpt */
Maxlcks= 10, /* max. query-type locks per domain name */
+ Maxauth= 16, /* proto for auth */
+ Maxmdns= 255, /* Limits for mDNS messages */
+ Maxdial= 271, /* port + trns + !! + host */
RRmagic= 0xdeadbabe,
DNmagic= 0xa110a110,
@@ -168,6 +171,7 @@
typedef struct Request Request;
typedef struct SOA SOA;
typedef struct Server Server;
+typedef struct Service Service;
typedef struct Sig Sig;
typedef struct Srv Srv;
typedef struct Txt Txt;
@@ -247,6 +251,21 @@
};
/*
+ * registry service
+ */
+struct Service
+{
+ Service *next;
+ char labl[Maxmdns]; /* Use mDNS limits */
+ char host[Maxmdns];
+ char mtpt[Maxpath];
+ char auth[Maxauth];
+ char trns[16]; /* transport tcp/ssh/gopher/carrierpidgeon */
+ char port[8]; /* 9fs, numerical, etc - switch to #? */
+ uchar perm; /* flag: from db */
+};
+
+/*
* an unpacked resource record
*/
struct RR
@@ -426,10 +445,13 @@
extern char *trace;
extern int traceactivity;
extern char *zonerefreshprogram;
+extern Service *registry;
#pragma varargck type "R" RR*
#pragma varargck type "Q" RR*
-
+#pragma varargck type "G" Service*
+#pragma varargck type "D" Service*
+#pragma varargck type "N" Service*
/* dn.c */
extern char *rrtname[];
@@ -463,7 +485,12 @@
int getactivity(Request*, int);
Area* inmyarea(char*);
void putactivity(int);
+void reg2cache(void);
+char* rstr2cache(char*, int);
+char* rstrdtch(char*);
+char* rstrupdt(char*);
RR* randomize(RR*);
+void reglog(char*, ...);
RR* rralloc(int);
void rrattach(RR*, int);
int rravfmt(Fmt*);
@@ -523,6 +550,9 @@
void dnnotify(DNSmsg*, DNSmsg*, Request*);
void notifyproc(void);
+/* reglookup.c */
+int openregistry(void);
+
/* convDNS2M.c */
int convDNS2M(DNSmsg*, uchar*, int);
diff -r 8127893f53b1 sys/src/cmd/ndb/mkfile
--- a/sys/src/cmd/ndb/mkfile Wed Aug 26 21:17:17 2020 -0700
+++ b/sys/src/cmd/ndb/mkfile Fri Aug 28 20:55:56 2020 -0700
@@ -13,6 +13,8 @@
dnstcp\
dnsdebug\
dnsgetip\
+ registry\
+ regquery\
ipquery\
inform\
@@ -49,6 +51,9 @@
$O.cs: cs.$O
$LD -o $target $prereq
+$O.registry: registry.$O reglookup.$O
+ $LD -o $target $prereq
+
$O.testipinfo: testipinfo.$O ipinfo.$O
$LD -o $target $prereq
diff -r 8127893f53b1 sys/src/cmd/ndb/registry.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/cmd/ndb/registry.c Fri Aug 28 20:55:56 2020 -0700
@@ -0,0 +1,896 @@
+#include <u.h>
+#include <libc.h>
+#include <auth.h>
+#include <fcall.h>
+#include <bio.h>
+#include <ip.h>
+#include "dns.h"
+
+enum
+{
+ Maxrequest= 1024,
+ Maxreply= 8192,
+ Maxrecords= 192,
+ Maxfdata= 8192,
+
+ Qdir= 0,
+ Qreg= 1,
+};
+
+typedef struct Mfile Mfile;
+typedef struct Job Job;
+typedef struct Records Records;
+
+struct Mfile
+{
+ Mfile *next;
+
+ char *user;
+ Qid qid;
+ int fid;
+
+ char reply[Maxreply];
+ ushort rr[Maxrecords]; /* offset of record */
+ ushort nrr; /* number of records */
+};
+
+/*
+ * active requests
+ */
+struct Job
+{
+ Job *next;
+ int flushed;
+ Fcall request;
+ Fcall reply;
+};
+Lock joblock;
+Job *joblist;
+
+struct {
+ Lock;
+ Mfile *inuse; /* active mfile's */
+} mfalloc;
+
+Service *registry;
+int vers;
+int debug;
+char *dbfile = "/lib/ndb/registry";
+char *reguser;
+char mntpt[Maxpath];
+int mfd[2];
+char *logfile = "registry";
+
+void rversion(Job*);
+void rflush(Job*);
+void rattach(Job*, Mfile*);
+char* rwalk(Job*, Mfile*);
+void ropen(Job*, Mfile*);
+void rcreate(Job*, Mfile*);
+void rread(Job*, Mfile*);
+void rwrite(Job*, Mfile*);
+void rclunk(Job*, Mfile*);
+void rremove(Job*, Mfile*);
+void rstat(Job*, Mfile*);
+void rwstat(Job*, Mfile*);
+void rauth(Job*);
+void mountinit(char*, char*);
+void setext(char*, int, char*);
+void io(void);
+
+char* addsrv(char*);
+char* rmsrv(char*);
+char* updatesrv(char*);
+void refresh(void);
+void regdump(char*);
+void sendmsg(Job*, char*);
+
+int scanfmt(Fmt*);
+int srvfmt(Fmt*);
+int dumpfmt(Fmt*);
+
+static char* query(Job*, Mfile*, char*, int);
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s [-xr] [-f ndb-file]\n", argv0);
+ exits("usage");
+}
+
+void
+main(int argc, char* argv[])
+{
+ char servefile[Maxpath], ext[Maxpath];
+ Dir *dir;
+
+ setnetmtpt(mntpt, sizeof mntpt, nil);
+ ext[0] = 0;
+
+ ARGBEGIN{
+ case 'd':
+ debug = 1;
+ break;
+ case 'f':
+ dbfile = EARGF(usage());
+ break;
+ case 'x':
+ setnetmtpt(mntpt, sizeof mntpt, EARGF(usage()));
+ setext(ext, sizeof ext, mntpt);
+ break;
+ } ARGEND;
+ if(argc != 0)
+ usage();
+
+ rfork(RFREND|RFNOTEG);
+
+ fmtinstall('F', fcallfmt);
+ fmtinstall('G', srvfmt);
+ fmtinstall('N', scanfmt);
+ fmtinstall('D', dumpfmt);
+
+ reglog("starting registry on %s", mntpt);
+
+ if(openregistry())
+ sysfatal("unable to open db file");
+
+ reguser = estrdup(getuser());
+ snprint(servefile, sizeof servefile, "#s/registry%s", ext);
+
+ dir = dirstat(servefile);
+ if (dir)
+ sysfatal("%s exists; another registry instance is running", servefile);
+ free(dir);
+
+ mountinit(servefile, mntpt);
+ reg2cache();
+ io();
+
+ _exits(0);
+}
+
+void
+setext(char *ext, int n, char *p)
+{
+ int i, c;
+
+ n--;
+ for(i = 0; i < n; i++){
+ c = p[i];
+ if(c == 0)
+ break;
+ if(c == '/')
+ c = '_';
+ ext[i] = c;
+ }
+ ext[i] = 0;
+}
+
+void
+mountinit(char *service, char *mntpt)
+{
+ int f;
+ int p[2];
+ char buf[32];
+
+ if(pipe(p) < 0)
+ sysfatal("pipe failed: %r");
+
+ /*
+ * make a /srv/registry
+ */
+ if((f = create(service, OWRITE|ORCLOSE, 0666)) < 0)
+ sysfatal("create %s failed: %r", service);
+ snprint(buf, sizeof buf, "%d", p[1]);
+ if(write(f, buf, strlen(buf)) != strlen(buf))
+ sysfatal("write %s failed: %r", service);
+
+ /* copy namespace to avoid a deadlock */
+ switch(rfork(RFFDG|RFPROC|RFNAMEG)){
+ case 0: /* child: start main proc */
+ close(p[1]);
+ procsetname("%s", mntpt);
+ break;
+ case -1:
+ sysfatal("fork failed: %r");
+ default: /* parent: make /srv/registry, mount it, exit */
+ close(p[0]);
+
+ /*
+ * put ourselves into the file system
+ */
+ if(mount(p[1], -1, mntpt, MAFTER, "") < 0)
+ fprint(2, "registry mount failed: %r\n");
+ _exits(0);
+ }
+ mfd[0] = mfd[1] = p[0];
+}
+
+Mfile*
+newfid(int fid, int needunused)
+{
+ Mfile *mf;
+
+ lock(&mfalloc);
+ for(mf = mfalloc.inuse; mf != nil; mf = mf->next)
+ if(mf->fid == fid){
+ unlock(&mfalloc);
+ if(needunused)
+ return nil;
+ return mf;
+ }
+ mf = emalloc(sizeof(*mf));
+ mf->fid = fid;
+ mf->qid.vers = vers;
+ mf->qid.type = QTDIR;
+ mf->qid.path = 0LL;
+ mf->user = estrdup(reguser);
+ mf->next = mfalloc.inuse;
+ mfalloc.inuse = mf;
+ unlock(&mfalloc);
+ return mf;
+}
+
+void
+freefid(Mfile *mf)
+{
+ Mfile **l;
+
+ lock(&mfalloc);
+ for(l = &mfalloc.inuse; *l != nil; l = &(*l)->next)
+ if(*l == mf){
+ *l = mf->next;
+ free(mf->user);
+ memset(mf, 0, sizeof *mf); /* cause trouble */
+ free(mf);
+ unlock(&mfalloc);
+ return;
+ }
+ unlock(&mfalloc);
+ sysfatal("freeing unused fid");
+}
+
+Mfile*
+copyfid(Mfile *mf, int fid)
+{
+ Mfile *nmf;
+
+ nmf = newfid(fid, 1);
+ if(nmf == nil)
+ return nil;
+ nmf->fid = fid;
+ free(nmf->user);
+ nmf->user = estrdup(mf->user);
+ nmf->qid.type = mf->qid.type;
+ nmf->qid.path = mf->qid.path;
+ nmf->qid.vers = vers++;
+ return nmf;
+}
+
+Job*
+newjob(void)
+{
+ Job *job;
+
+ job = emalloc(sizeof *job);
+ lock(&joblock);
+ job->next = joblist;
+ joblist = job;
+ job->request.tag = -1;
+ unlock(&joblock);
+ return job;
+}
+
+void
+freejob(Job *job)
+{
+ Job **l;
+
+ lock(&joblock);
+ for(l = &joblist; *l; l = &(*l)->next)
+ if(*l == job){
+ *l = job->next;
+ memset(job, 0, sizeof *job); /* cause trouble */
+ free(job);
+ break;
+ }
+ unlock(&joblock);
+}
+
+void
+flushjob(int tag)
+{
+ Job *job;
+
+ lock(&joblock);
+ for(job = joblist; job; job = job->next)
+ if(job->request.tag == tag && job->request.type != Tflush){
+ job->flushed = 1;
+ break;
+ }
+ unlock(&joblock);
+}
+
+void
+io(void)
+{
+ long n;
+ Mfile *mf;
+ uchar mdata[IOHDRSZ + Maxfdata];
+ Job *job;
+
+ while((n = read9pmsg(mfd[0], mdata, sizeof mdata)) != 0){
+ if(n < 0){
+ syslog(1, logfile, "error reading 9P from %s: %r", mntpt);
+ break;
+ }
+
+ job = newjob();
+ if(convM2S(mdata, n, &job->request) != n){
+ reglog("format error %ux %ux %ux %ux %ux",
+ mdata[0], mdata[1], mdata[2], mdata[3], mdata[4]);
+ freejob(job);
+ break;
+ }
+ mf = newfid(job->request.fid, 0);
+ if(debug)
+ reglog("%F", &job->request);
+
+ switch(job->request.type){
+ default:
+ warning("unknown request type %d", job->request.type);
+ break;
+ case Tversion:
+ rversion(job);
+ break;
+ case Tauth:
+ rauth(job);
+ break;
+ case Tflush:
+ rflush(job);
+ break;
+ case Tattach:
+ rattach(job, mf);
+ break;
+ case Twalk:
+ rwalk(job, mf);
+ break;
+ case Topen:
+ ropen(job, mf);
+ break;
+ case Tcreate:
+ rcreate(job, mf);
+ break;
+ case Tread:
+ rread(job, mf);
+ break;
+ case Twrite:
+ rwrite(job, mf);
+ break;
+ case Tclunk:
+ rclunk(job, mf);
+ break;
+ case Tremove:
+ rremove(job, mf);
+ break;
+ case Tstat:
+ rstat(job, mf);
+ break;
+ case Twstat:
+ rwstat(job, mf);
+ break;
+ }
+
+ freejob(job);
+ }
+}
+
+void
+rversion(Job *job)
+{
+ if(job->request.msize > IOHDRSZ + Maxfdata)
+ job->reply.msize = IOHDRSZ + Maxfdata;
+ else
+ job->reply.msize = job->request.msize;
+ job->reply.version = "9P2000";
+ if(strncmp(job->request.version, "9P", 2) != 0)
+ job->reply.version = "unknown";
+ sendmsg(job, nil);
+}
+
+void
+rauth(Job *job)
+{
+ sendmsg(job, "registry: authentication not required");
+}
+
+void
+rflush(Job *job)
+{
+ flushjob(job->request.oldtag);
+ sendmsg(job, 0);
+}
+
+void
+rattach(Job *job, Mfile *mf)
+{
+ if(mf->user != nil)
+ free(mf->user);
+ mf->user = estrdup(job->request.uname);
+ mf->qid.vers = vers++;
+ mf->qid.type = QTDIR;
+ mf->qid.path = 0LL;
+ job->reply.qid = mf->qid;
+ sendmsg(job, 0);
+}
+
+char*
+rwalk(Job *job, Mfile *mf)
+{
+ int i, nelems;
+ char *err;
+ char **elems;
+ Mfile *nmf;
+ Qid qid;
+
+ err = 0;
+ nmf = nil;
+ elems = job->request.wname;
+ nelems = job->request.nwname;
+ job->reply.nwqid = 0;
+
+ if(job->request.newfid != job->request.fid){
+ /* clone fid */
+ nmf = copyfid(mf, job->request.newfid);
+ if(nmf == nil){
+ err = "clone bad newfid";
+ goto send;
+ }
+ mf = nmf;
+ }
+ /* else nmf will be nil */
+
+ qid = mf->qid;
+ if(nelems > 0){
+ /* walk fid */
+ for(i=0; i<nelems && i<MAXWELEM; i++){
+ if((qid.type & QTDIR) == 0){
+ err = "not a directory";
+ break;
+ }
+ if(strcmp(elems[i], "..") == 0 || strcmp(elems[i], ".") == 0){
+ qid.type = QTDIR;
+ qid.path = Qdir;
+ Found:
+ job->reply.wqid[i] = qid;
+ job->reply.nwqid++;
+ continue;
+ }
+ if(strcmp(elems[i], "registry") == 0){
+ qid.type = QTFILE;
+ qid.path = Qreg;
+ goto Found;
+ }
+ err = "file does not exist";
+ break;
+ }
+ }
+
+ send:
+ if(nmf != nil && (err!=nil || job->reply.nwqid<nelems))
+ freefid(nmf);
+ if(err == nil)
+ mf->qid = qid;
+ sendmsg(job, err);
+ return err;
+}
+
+void
+ropen(Job *job, Mfile *mf)
+{
+ int mode;
+ char *err;
+
+ err = 0;
+ mode = job->request.mode;
+ if(mf->qid.type & QTDIR)
+ if(mode)
+ err = "permission denied";
+ job->reply.qid = mf->qid;
+ job->reply.iounit = 0;
+ sendmsg(job, err);
+}
+
+void
+rcreate(Job *job, Mfile *mf)
+{
+ USED(mf);
+ sendmsg(job, "creation permission denied");
+}
+
+void rclunk(Job *job, Mfile *mf)
+{
+ freefid(mf);
+ sendmsg(job, 0);
+}
+
+void
+rremove(Job *job, Mfile *mf)
+{
+ USED(mf);
+ sendmsg(job, "remove permission denied");
+}
+
+void
+rread(Job *job, Mfile *mf)
+{
+ int i, n;
+ long clock;
+ ulong cnt;
+ vlong off;
+ char *err;
+ uchar buf[Maxfdata];
+ Dir dir;
+
+ n = 0;
+ err = nil;
+ off = job->request.offset;
+ cnt = job->request.count;
+ *buf = '\0';
+ job->reply.data = (char*)buf;
+ if(mf->qid.type & QTDIR){
+ clock = time(nil);
+ if(off == 0){
+ memset(&dir, 0, sizeof dir);
+ dir.name = "registry";
+ dir.qid.type = QTFILE;
+ dir.qid.vers = vers;
+ dir.qid.path = Qreg;
+ dir.mode = 0666;
+ dir.length = 0;
+ dir.uid = dir.gid = dir.muid = mf->user;
+ dir.atime = dir.mtime = clock;
+ n = convD2M(&dir, buf, sizeof buf);
+ }
+ } else if (off < 0)
+ err = "negative read offset";
+ else {
+ for(i = 1; i < mf->nrr; i++)
+ if(mf->rr[i] > off)
+ break;
+ if(i <= mf->nrr){
+ if(off + cnt > mf->rr[i])
+ n = mf->rr[i] - off;
+ else
+ n = cnt;
+ assert(n >= 0);
+ job->reply.data = mf->reply + off;
+ }
+ }
+ job->reply.count = n;
+ sendmsg(job, err);
+}
+
+void
+rwrite(Job *job, Mfile *mf)
+{
+ int send, pipe2rc;
+ ulong cnt;
+ char *err, *atype;
+ char errbuf[ERRMAX];
+
+ err = nil;
+ cnt = job->request.count;
+ send = 1;
+ if(mf->qid.type & QTDIR)
+ err = "can't write directory";
+ else if (job->request.offset != 0)
+ err = "writing at non-zero offset";
+ else if (cnt >= Maxrequest)
+ err = "request too long";
+ else
+ send = 0;
+ if(send)
+ goto send;
+
+ job->request.data[cnt] = 0;
+ if(cnt > 0 && job->request.data[cnt-1] == '\n')
+ job->request.data[cnt-1] = 0;
+
+ if(strcmp(mf->user, "none") == 0 || strcmp(mf->user, reguser) != 0)
+ goto query; /* We don't want remote clients to modify our local */
+
+ /*
+ * special commands
+ */
+ send = 1;
+ if(strcmp(job->request.data, "debug")==0)
+ debug ^= 1;
+ else if(strcmp(job->request.data, "dump")==0)
+ regdump("/lib/ndb/regdump");
+ else if (strcmp(job->request.data, "refresh")==0)
+ refresh();
+ else if (strncmp(job->request.data, "add ", 4)==0)
+ err = addsrv(job->request.data + 4);
+ else if (strncmp(job->request.data, "rm ", 3)==0)
+ err = rmsrv(job->request.data + 3);
+ else if (strncmp(job->request.data, "update ", 7)==0)
+ err = updatesrv(job->request.data + 7);
+ else
+ send = 0;
+ if (send)
+ goto send;
+
+query:
+ /*
+ * kill previous reply
+ */
+ mf->nrr = 0;
+ mf->rr[0] = 0;
+ pipe2rc = 0;
+
+ atype = strchr(job->request.data, ' ');
+ if(atype == 0){
+ snprint(errbuf, sizeof errbuf, "illegal request %s", job->request.data);
+ err = errbuf;
+ goto send;
+ } else
+ *atype++ = 0;
+
+ if(strcmp(atype, "srv") == 0)
+ pipe2rc++;
+ else if(strcmp(atype, "scan") != 0){
+ snprint(errbuf, sizeof errbuf, "unknown query %s", atype);
+ err = errbuf;
+ goto send;
+ }
+
+ err = query(job, mf,job->request.data, pipe2rc);
+send:
+ job->reply.count = cnt;
+ sendmsg(job, err);
+}
+
+void
+rstat(Job *job, Mfile *mf)
+{
+ Dir dir;
+ uchar buf[IOHDRSZ+Maxfdata];
+
+ memset(&dir, 0, sizeof dir);
+ if(mf->qid.type & QTDIR){
+ dir.name = ".";
+ dir.mode = DMDIR|0555;
+ }else{
+ dir.name = "registry";
+ dir.mode = 0666;
+ }
+ dir.qid = mf->qid;
+ dir.length = 0;
+ dir.uid = dir.gid = dir.muid = mf->user;
+ dir.atime = dir.mtime = time(nil);
+ job->reply.nstat = convD2M(&dir, buf, sizeof buf);
+ job->reply.stat = buf;
+ sendmsg(job, 0);
+}
+
+void
+rwstat(Job *job, Mfile *mf)
+{
+ USED(mf);
+ sendmsg(job, "wstat permission denied");
+}
+
+static char *
+query(Job *job, Mfile *mf, char *p, int pipe2rc)
+{
+ int n;
+
+ Service *c;
+ lock(&joblock);
+ if(!job->flushed){
+ n = 0;
+ mf->nrr = 0;
+ for(c = registry; c && n < Maxreply; c = c->next)
+ if((strncmp(p, c->labl, strlen(p))==0) || (strcmp(p, "all")==0)){
+ mf->rr[mf->nrr++] = n;
+ if(pipe2rc)
+ n += snprint(mf->reply+n, Maxreply-n, "%G", c);
+ else
+ n += snprint(mf->reply+n, Maxreply-n, "%N", c);
+ }
+ mf->rr[mf->nrr] = n;
+ }
+ unlock(&joblock);
+ return nil;
+}
+
+void
+sendmsg(Job *job, char *err)
+{
+ int n;
+ uchar mdata[IOHDRSZ+Maxfdata];
+ char ename[ERRMAX];
+
+ if(err){
+ job->reply.type = Rerror;
+ snprint(ename, sizeof ename, "registry: %s", err);
+ job->reply.ename = ename;
+ }else
+ job->reply.type = job->request.type+1;
+ job->reply.tag = job->request.tag;
+ n = convS2M(&job->reply, mdata, sizeof mdata);
+ if(n == 0){
+ warning("sendmsg convS2M of %F returns 0", &job->reply);
+ abort();
+ }
+ lock(&joblock);
+ if(job->flushed == 0)
+ if(write(mfd[1], mdata, n)!=n)
+ sysfatal("mount write");
+ unlock(&joblock);
+ if(debug)
+ reglog("%F %d", &job->reply, n);
+}
+
+void
+regdump(char *file)
+{
+ Service *rp;
+ int fd;
+
+ fd = create(file, OWRITE, 0666);
+ if(fd < 0)
+ return;
+ lock(&mfalloc);
+ for(rp = registry; rp; rp = rp->next)
+ fprint(fd, "%D\n\n", rp);
+ unlock(&mfalloc);
+ close(fd);
+}
+
+void
+refresh(void)
+{
+ Service *c;
+ char dial[Maxdial];
+
+ for(c = registry; c; c = c->next){
+ /* Don't remove the ones we've added since startup */
+ if(!c->perm)
+ continue;
+ snprint(dial, Maxdial, "%s!%s!%s", c->trns, c->host, c->port);
+ rmsrv(dial);
+ /* Reset so we don't have messy loops */
+ c = registry;
+ }
+ reg2cache();
+}
+
+char *
+addsrv(char *args)
+{
+ if(debug)
+ reglog("Adding entry: %s", args);
+
+ return rstr2cache(args, 0);
+}
+
+char *
+rmsrv(char *args)
+{
+ if(debug)
+ reglog("Removing entry: %s", args);
+
+ return rstrdtch(args);
+}
+
+char *
+updatesrv(char *args)
+{
+ if(debug)
+ reglog("Updating entry: %s", args);
+
+ return rstrupdt(args);
+}
+
+void
+warning(char *fmt, ...)
+{
+ char regerr[256];
+ va_list arg;
+
+ va_start(arg, fmt);
+ vseprint(regerr, regerr+sizeof(regerr), fmt, arg);
+ va_end(arg);
+ syslog(1, logfile, regerr);
+}
+
+void
+reglog(char *fmt, ...)
+{
+ char regerr[256];
+ va_list arg;
+
+ va_start(arg, fmt);
+ vseprint(regerr, regerr+sizeof(regerr), fmt, arg);
+ va_end(arg);
+ syslog(0, logfile, regerr);
+}
+
+void*
+emalloc(int size)
+{
+ void *x;
+
+ x = malloc(size);
+ if(x == nil)
+ sysfatal("out of memory");
+ memset(x, 0, size);
+ return x;
+}
+
+char*
+estrdup(char *s)
+{
+ int size;
+ char *p;
+
+ size = strlen(s);
+ p = malloc(size+1);
+ if(p == nil)
+ sysfatal("out of memory");
+ memmove(p, s, size);
+ p[size] = 0;
+ return p;
+}
+
+int
+srvfmt(Fmt *f)
+{
+ Service *r;
+ char mf[Maxpath+1], auth[7];
+
+ r = va_arg(f->args, Service*);
+ mf[0] = 0;
+ auth[0] = 0;
+
+ if(strcmp(r->mtpt, "")!= 0)
+ snprint(mf, sizeof(r->mtpt)+1, " %s", r->mtpt);
+
+ if(strcmp(r->auth, "none")==0)
+ snprint(auth, 4, "srv");
+ else
+ snprint(auth, 7, "srvtls");
+
+ return fmtprint(f, "%s %s!%s!%s '%s'%s",
+ auth, r->trns, r->host, r->port, r->labl, mf);
+}
+
+int
+scanfmt(Fmt *f)
+{
+ Service *r;
+ char mf[Maxpath+6]; /* pad for our tuple attrs */
+
+ mf[0] = 0;
+ r = va_arg(f->args, Service*);
+ if(strcmp(r->mtpt, "")!=0)
+ snprint(mf, sizeof(r->mtpt)+6, " mtpt=%s", r->mtpt);
+ return fmtprint(f, "service=%s!%s!%s label='%s' auth=%s%s",
+ r->trns, r->host, r->port, r->labl, r->auth, mf);
+}
+
+int
+dumpfmt(Fmt *f)
+{
+ Service *r;
+ char mf[Maxpath+7]; /* pad for our tuple attrs */
+
+ r = va_arg(f->args, Service*);
+ if(r->mtpt != 0)
+ snprint(mf, sizeof(r->mtpt) + 7, "\n\tmtpt=%s", r->mtpt);
+ return fmtprint(f, "service=%s!%s!%s\n\tlabel=%s\n\tauth=%s%s",
+ r->trns, r->host, r->port, r->labl, r->auth, mf);
+}
+
diff -r 8127893f53b1 sys/src/cmd/ndb/reglookup.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/cmd/ndb/reglookup.c Fri Aug 28 20:55:56 2020 -0700
@@ -0,0 +1,204 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ndb.h>
+#include "dns.h"
+
+static Ndb *db;
+static QLock dblock;
+
+int
+openregistry(void)
+{
+ if(db != nil)
+ return 0;
+
+ db = ndbopen(dbfile);
+ return db!=nil ? 0: -1;
+}
+
+static void
+attach(Service* svc, int persist)
+{
+ svc->perm = !!persist;
+
+ if(registry != nil){
+ svc->next = registry;
+ }
+
+ svc->next = registry;
+ registry = svc;
+}
+
+static char*
+detach(char *dial)
+{
+ Service *c, *last = 0;
+ char buf[Maxdial]; /* trns is capped at 16, port 8 */
+
+ for(c = registry; c; c = c->next){
+ snprint(buf, Maxdial, "%s!%s!%s", c->trns, c->host, c->port);
+ if(strcmp(buf, dial)==0){
+ if(last == 0)
+ registry = c->next;
+ else
+ last->next = c->next;
+ free(c);
+ return 0;
+ }
+ last = c;
+ }
+
+ return "found no matching service";
+}
+
+static void
+host2svc(Service *svc, char *dial)
+{
+ int n;
+
+ /*
+ * entry host=tcp!mything!9fs
+ * for now, tokenize but we should allow short strings
+ */
+ n = strcspn(dial, "!");
+ if(n < 1)
+ strcpy(svc->trns, "tcp");
+ else
+ strecpy(svc->trns, svc->trns+n+1, dial);
+ dial = dial + n + 1;
+
+ n = strcspn(dial, "!");
+ strecpy(svc->host, svc->host+n+1, dial);
+
+ dial = dial + n + 1;
+ if(sizeof(dial) < 1)
+ strcpy(svc->port, "9fs");
+ else if(sizeof(dial) > 8)
+ /* If this starts happening, we should bump the number */
+ strecpy(svc->port, svc->port + 8, dial);
+ else
+ strcpy(svc->port, dial);
+}
+
+static void
+dbtuple2cache(Ndbtuple *t, int persist)
+{
+ Ndbtuple *et, *nt;
+ Service *svc;
+
+
+ for(et = t; et; et = et->entry)
+ if(strncmp(et->attr, "serv", 4)==0){
+ svc = emalloc(sizeof(*svc));
+ host2svc(svc, et->val);
+ for(nt = et->entry; nt; nt = nt->entry)
+ if(strcmp(nt->attr, "label")==0)
+ strecpy(svc->labl, svc->labl+Maxmdns, nt->val);
+ else if(strcmp(nt->attr, "auth")==0)
+ strecpy(svc->auth, svc->auth+Maxauth, nt->val);
+ else if(strcmp(nt->attr, "mtpt")==0)
+ strecpy(svc->mtpt, svc->mtpt+Maxpath, nt->val);
+ attach(svc, persist);
+ };
+}
+
+static void
+dbfile2cache(Ndb *db)
+{
+ Ndbtuple *t;
+
+ if(debug)
+ reglog("reading %s", db->file);
+ Bseek(&db->b, 0, 0);
+ while(t = ndbparse(db)){
+ dbtuple2cache(t, 1);
+ ndbfree(t);
+ }
+
+
+}
+
+/* For now, we expect properly formatted strings */
+char*
+rstr2cache(char *entry, int persist)
+{
+ Service *svc;
+ char *args[7];
+
+ int i, n;
+
+ n = tokenize(entry, args, 7);
+
+ svc = emalloc(sizeof(*svc));
+ host2svc(svc, estrdup(args[0]));
+
+ for(i = 1; i < n - 1; i++)
+ if(strcmp(args[i], "label")==0)
+ strecpy(svc->labl, svc->labl+Maxmdns, args[++i]);
+ else if(strcmp(args[i], "auth")==0)
+ strecpy(svc->auth, svc->auth+Maxauth, args[++i]);
+ else if(strcmp(args[i], "mtpt")==0)
+ strecpy(svc->mtpt, svc->mtpt+Maxpath, args[++i]);
+ attach(svc, persist);
+ return 0;
+}
+
+char*
+rstrdtch(char *svc)
+{
+ return detach(svc);
+}
+
+/* e.g. update tcp!foo!9fs label newlabel */
+char*
+rstrupdt(char *entry)
+{
+ Service *c, *svc = 0;
+ char *args[7], buf[Maxdial];
+ int i, n;
+
+ n = tokenize(entry, args, 7);
+
+ /* Find our service */
+ for(c = registry; c; c = c->next){
+ snprint(buf, Maxdial, "%s!%s!%s", c->trns, c->host, c->port);
+ if(strcmp(buf, args[0])==0){
+ svc = c;
+ break;
+ }
+ }
+
+ if(svc == 0)
+ return "found no matching service";
+
+ for(i = 1; i < n - 1; i++)
+ if(strcmp(args[i], "label")==0)
+ strecpy(svc->labl, svc->labl+Maxmdns, args[++i]);
+ else if(strcmp(args[i], "auth")==0)
+ strecpy(svc->auth, svc->auth+Maxauth, args[++i]);
+ else if(strcmp(args[i], "mtpt")==0)
+ strecpy(svc->mtpt, svc->mtpt+Maxpath, args[++i]);
+
+ return 0;
+}
+
+void
+reg2cache(void)
+{
+ Ndb *ndb;
+
+ qlock(&dblock);
+ if(openregistry() < 0){
+ qunlock(&dblock);
+ return;
+ }
+
+ if(debug)
+ syslog(0, logfile, "building cache from db");
+
+ for(ndb = db; ndb; ndb = ndb->next)
+ dbfile2cache(ndb);
+
+ qunlock(&dblock);
+}
diff -r 8127893f53b1 sys/src/cmd/ndb/regquery.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/cmd/ndb/regquery.c Fri Aug 28 20:55:56 2020 -0700
@@ -0,0 +1,69 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ctype.h>
+#include <ndb.h>
+#include "dns.h"
+#include "ip.h"
+
+void
+usage(void)
+{
+ fprint(2, "usage: regquery [-s] [-f registry] query\n");
+ exits("usage");
+}
+
+static void
+queryregistry(int fd, char *line, int n)
+{
+ char buf[8192+1];
+
+ seek(fd, 0, 0);
+ write(fd, line, n);
+
+ seek(fd, 0, 0);
+ while((n = read(fd, buf, sizeof(buf)-1)) > 0){
+ buf[n++] = '\n';
+ write(1, buf, n);
+ }
+}
+
+static void
+query(int fd, char *q, int pipe2rc)
+{
+ char arg[260];
+
+ if(strlen(q) > 255)
+ sysfatal("query too long");
+
+ sprint(arg, "%s %s", q, (pipe2rc) ? "srv":"scan");
+ queryregistry(fd, arg, sizeof(arg));
+}
+
+void
+main(int argc, char *argv[])
+{
+ int fd, pipe2rc = 0;
+ char *rst = "/net/registry";
+
+ ARGBEGIN {
+ case 's':
+ pipe2rc++;
+ break;
+ case 'f':
+ rst = EARGF(usage());
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if(argc != 1)
+ usage();
+
+ fd = open(rst, ORDWR);
+ if(fd < 0)
+ sysfatal("can't open %s: %r", rst);
+
+ query(fd, argv[0], pipe2rc);
+ exits(0);
+}
next reply other threads:[~2020-08-29 4:17 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-08-29 4:17 Michael Misch [this message]
2020-09-01 4:57 ` [9front] ndb/registry ori
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=324735A7-38EE-4288-87B3-765667AEF962@gmail.com \
--to=michaelmisch1985@gmail.com \
--cc=9front@9front.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).