From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pl1-f172.google.com ([209.85.214.172]) by ewsd; Sat Aug 29 00:17:48 EDT 2020 Received: by mail-pl1-f172.google.com with SMTP id k13so550830plk.13 for <9front@9front.org>; Fri, 28 Aug 2020 21:17:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:mime-version:subject:message-id:date:to; bh=SFbvfgx/sNah9w9dS4VVt2oCXhudo/RGkV38/OA1WWo=; b=VE16l5bNjuANmU6WJT82IL46AJQSGcG5KBrj4dz5qcyccM7R+kSxiw6T4qz609kMhw Ms4vlFtaJW7Qx9VlGjO399t3IjzERupp1dYaq8jbQGSiw6aEBwB/Mz6mRsgCTDiJOzp2 qhexXvsgmujJbWPd13r4GzRfdVTpgzwNZ0HMKKp+rMoaWONrQYTyBXCklE/pMOoVYDY/ EMG3mA212TWOtLHkNgOjiCJUP5hTB6+15jAdK+HSr/kDTqEOhZdXaq/p8XWm8HfauEjl QiviWpe4dPFw+vfZV+H8XiHoSw9bhTvp39x7KW1ykS0P/XAOlThgOy2hAc1cCql8kiPV l5Jw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:mime-version:subject:message-id:date:to; bh=SFbvfgx/sNah9w9dS4VVt2oCXhudo/RGkV38/OA1WWo=; b=MqN3/90hr6dnvmWhRqzLScKjK3LSw62f4sZvcQrRMdqK8DaIVZaS0O8UlgB5yvMx4T Ju5z6xsYwOeAxuXNxbwOmrgEmmqwvwRmh8bG1yfaEIJmC8abWunVakFJRM4aOI09uK7Y LpumaG35RgBPAUXhvMBUCwJCDkWpZMFApCXmGnYFUSsBHm7/nMF0OJR0qORZeUMeMglQ XiuB9lZgXCm0Ar8Az6l3WFzbESTQeAsiNpGoxsLrtMZAywn7lgDvwSHDfZ/325WyC+aV eNPwLXc6Meff+ByXGaLTEfVFAaQZsFal7guKoVrJF9NB8teUGxsEQtG51n43ViJRTTUl JTzg== X-Gm-Message-State: AOAM531nK4p5tLex35/7aj9ww1akLEYdBUnd4RxWwLZFksrhVO/iCd9M KTkuyICSmDvSprRfJsBMgFMk2vacHDyw2Q== X-Google-Smtp-Source: ABdhPJw7erBT9HFZC3RAUWSJCK9c7QIJ1Xfag3XyWy5oM6atkhTlCDB1O/O56LHt4XUmj/CewmGEcw== X-Received: by 2002:a17:90a:c253:: with SMTP id d19mr1754963pjx.113.1598674663029; Fri, 28 Aug 2020 21:17:43 -0700 (PDT) Return-Path: Received: from halfwits-mbp.lan ([104.246.165.139]) by smtp.gmail.com with ESMTPSA id n4sm1007049pfa.21.2020.08.28.21.17.41 for <9front@9front.org> (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 28 Aug 2020 21:17:42 -0700 (PDT) From: Michael Misch X-Google-Original-From: Michael Misch Content-Type: multipart/mixed; boundary="Apple-Mail=_3AD05A2C-78B2-4392-A74C-82E8D33F7598" Mime-Version: 1.0 (Mac OS X Mail 13.4 \(3608.120.23.2.1\)) Subject: ndb/registry Message-Id: <324735A7-38EE-4288-87B3-765667AEF962@gmail.com> Date: Fri, 28 Aug 2020 21:17:40 -0700 To: 9front@9front.org X-Mailer: Apple Mail (2.3608.120.23.2.1) List-ID: <9front.9front.org> List-Help: X-Glyph: ➈ X-Bullshit: rich-client polling framework --Apple-Mail=_3AD05A2C-78B2-4392-A74C-82E8D33F7598 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 Hey, I=E2=80=99ve 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.=20 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=E2=80=99re in regular ndb format, and = look like service=3Dtcp!myipaddr!1234 auth=3Dnone label=3Dmyservice mtpt=3D/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=E2=80=99ve added after startup untouched.=20 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=3Dtcp!myservice!1234 label=3Dgridchat auth=3Dnone mtpt=3D/n/chat [ =E2=80=A6 ] // any other matches ndb/regquery -s grid=20 srv tcp!myservice!1234 gridchat /n/chat [ =E2=80=A6 ] // 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=E2=80=99t caught! I=E2=80=99l= l include the diff here, thanks! - halfwit=20 --Apple-Mail=_3AD05A2C-78B2-4392-A74C-82E8D33F7598 Content-Disposition: attachment; filename=ndb.patch Content-Type: application/octet-stream; x-unix-mode=0664; name="ndb.patch" Content-Transfer-Encoding: 7bit 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 +#include +#include +#include +#include +#include +#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; ireply.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.nwqidqid = 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 +#include +#include +#include +#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 +#include +#include +#include +#include +#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); +} --Apple-Mail=_3AD05A2C-78B2-4392-A74C-82E8D33F7598--