Merge branch 'front' of git://git.9front.org/plan9front/plan9front into front

This commit is contained in:
xfnw 2022-06-30 11:42:24 -04:00
commit c97daf119d
6 changed files with 461 additions and 431 deletions

View file

@ -5,8 +5,6 @@ srv \- server registry
.nf .nf
.B bind #s /srv .B bind #s /srv
.BI #s/ clone
.BI #s/ n
.BI #s/ service1 .BI #s/ service1
.BI #s/ service2 .BI #s/ service2
... ...
@ -14,7 +12,7 @@ srv \- server registry
.SH DESCRIPTION .SH DESCRIPTION
The The
.I srv .I srv
device provides a tree of directories holding device provides a one-level directory holding
already-open channels to services. already-open channels to services.
In effect, In effect,
.I srv .I srv
@ -42,18 +40,6 @@ releases that reference.
.PP .PP
It is an error to write more than one number into a server file, It is an error to write more than one number into a server file,
or to create a file with a name that is already being used. or to create a file with a name that is already being used.
.PP
Opening the
.I clone
file allocates a new service directory. Reading
.I clone
returns the id of the new directory. This new service
directory can then be accessed at
.BR /srv/id .
Directories are recursable; each new service directory
contains its own
.I clone
file.
.SH EXAMPLE .SH EXAMPLE
To drop one end of a pipe into To drop one end of a pipe into
.BR /srv , .BR /srv ,

View file

@ -5,249 +5,80 @@
#include "fns.h" #include "fns.h"
#include "../port/error.h" #include "../port/error.h"
#include "netif.h"
typedef struct Link Link;
struct Link
{
void *link;
char *name;
ulong path;
};
typedef struct Srv Srv; typedef struct Srv Srv;
struct Srv struct Srv
{ {
Link; char *name;
char *owner; char *owner;
ulong perm; ulong perm;
Chan *chan; Chan *chan;
Srv *link;
ulong path;
}; };
typedef struct Board Board; static QLock srvlk;
struct Board static Srv *srv;
static int qidpath;
static Srv*
srvlookup(char *name, ulong qidpath)
{ {
Link; Srv *sp;
RWlock;
Ref;
Board *parent; for(sp = srv; sp != nil; sp = sp->link) {
Board *child; if(sp->path == qidpath || (name != nil && strcmp(sp->name, name) == 0))
Srv *srv; return sp;
long id;
int qidpath;
int closed;
};
struct{
QLock;
long path;
} boards;
enum{
Qroot,
Qclone,
Qlease,
Qend,
};
Board root;
static char Eexpired[] = "expired lease";
static void*
lookup(Link *l, char *name, ulong qidpath)
{
Link *lp;
if(qidpath != ~0UL)
qidpath = NETTYPE(qidpath);
for(lp = l; lp != nil; lp = lp->link){
if(qidpath != ~0UL && lp->path == qidpath)
return lp;
if(name != nil && strcmp(lp->name, name) == 0)
return lp;
} }
return nil; return nil;
} }
static void*
remove(Link **l, char *name, ulong qidpath)
{
Link *lp;
Link **last;
if(qidpath != ~0UL)
qidpath = NETTYPE(qidpath);
last = l;
for(lp = *l; lp != nil; lp = lp->link){
if(qidpath != ~0UL && lp->path == qidpath)
break;
if(name != nil && strcmp(lp->name, name) == 0)
break;
last = &lp->link;
}
if(lp == nil)
return nil;
*last = lp->link;
lp->link = nil;
return lp;
}
static void
boardclunk(Board *b, int close)
{
Srv *sp, *prv;
Board *ch;
long ref;
/* caller holds a wlock */
if(b == &root){
wunlock(b);
return;
}
if(close){
assert(b->closed == 0);
b->closed++;
for(sp = b->srv; sp != nil; sp = prv){
prv = sp->link;
free(sp->owner);
free(sp->name);
if(sp->chan != nil)
cclose(sp->chan);
free(sp);
}
b->srv = nil;
}
ref = decref(b);
/*
* All boards must be walkable from root. So a board
* is allowed to sit at zero references as long as it
* still has active children. For leaf nodes we then
* have to walk up the tree to clear now empty parents.
*/
while(b->closed && b->child == nil && ref == 0){
//Root should never be closed
assert(b->parent != nil);
wlock(b->parent);
ch = remove((Link**)&b->parent->child, b->name, b->path);
assert(ch == b);
b = ch->parent;
free(ch->name);
wunlock(ch);
free(ch);
}
wunlock(b);
}
static int static int
srvgen(Chan *c, char *name, Dirtab*, int, int s, Dir *dp) srvgen(Chan *c, char *name, Dirtab*, int, int s, Dir *dp)
{ {
Srv *sp; Srv *sp;
Board *b, *ch;
Qid q; Qid q;
if(name != nil && strlen(name) >= sizeof(up->genbuf))
return -1;
b = c->aux;
ch = nil;
mkqid(&q, ~0L, 0, QTFILE);
rlock(b);
if(waserror()){
runlock(b);
return -1;
}
if(s == DEVDOTDOT){ if(s == DEVDOTDOT){
ch = b->parent; devdir(c, c->qid, "#s", 0, eve, 0555, dp);
if(ch == nil) return 1;
ch = &root;
goto Child;
} }
if(name != nil){
if(strcmp("clone", name) == 0)
goto Clone;
sp = lookup(b->srv, name, ~0UL); qlock(&srvlk);
if(sp == nil) if(name != nil)
ch = lookup(b->child, name, ~0UL); sp = srvlookup(name, -1);
} else { else {
if(s == 0) for(sp = srv; sp != nil && s > 0; sp = sp->link)
goto Clone;
s--;
for(sp = b->srv; sp != nil && s > 0; sp = sp->link)
s--;
for(ch = b->child; ch != nil && s > 0; ch = ch->link)
s--; s--;
} }
if(sp != nil){ if(sp == nil || (name != nil && (strlen(sp->name) >= sizeof(up->genbuf)))) {
kstrcpy(up->genbuf, sp->name, sizeof up->genbuf); qunlock(&srvlk);
q.vers = NETID(c->qid.path); return -1;
q.path = NETQID(q.vers, sp->path); }
devdir(c, q, up->genbuf, 0, sp->owner, sp->perm, dp); mkqid(&q, sp->path, 0, QTFILE);
} else if(ch != nil){ /* make sure name string continues to exist after we release lock */
Child: kstrcpy(up->genbuf, sp->name, sizeof up->genbuf);
kstrcpy(up->genbuf, ch->name, sizeof up->genbuf); devdir(c, q, up->genbuf, 0, sp->owner, sp->perm, dp);
q.vers = ch->id; qunlock(&srvlk);
q.path = NETQID(q.vers, ch->path);
q.type = QTDIR;
devdir(c, q, up->genbuf, 0, eve, 0555|DMDIR, dp);
/* dirread's and stats shouldn't alter c->aux */
if(name != nil)
c->aux = ch;
} else if(0){
Clone:
q.vers = NETID(c->qid.path);
q.path = NETQID(q.vers, Qclone);
devdir(c, q, "clone", 0, eve, 0444, dp);
} else
error(Enonexist);
runlock(b);
poperror();
return 1; return 1;
} }
static void static void
srvinit(void) srvinit(void)
{ {
root.qidpath = Qend; qidpath = 1;
root.name = "#s";
} }
static Chan* static Chan*
srvattach(char *spec) srvattach(char *spec)
{ {
Chan *c; return devattach('s', spec);
c = devattach('s', spec);
c->aux = &root;
return c;
} }
static Walkqid* static Walkqid*
srvwalk(Chan *c, Chan *nc, char **name, int nname) srvwalk(Chan *c, Chan *nc, char **name, int nname)
{ {
Board *b; return devwalk(c, nc, name, nname, 0, 0, srvgen);
Walkqid *wq;
wq = devwalk(c, nc, name, nname, 0, 0, srvgen);
if(wq == nil || wq->clone == nil)
return wq;
b = wq->clone->aux;
if(b == &root)
return wq;
incref(b);
return wq;
} }
static int static int
@ -259,14 +90,12 @@ srvstat(Chan *c, uchar *db, int n)
char* char*
srvname(Chan *c) srvname(Chan *c)
{ {
Board *b;
Srv *sp; Srv *sp;
char *s; char *s;
s = nil; s = nil;
b = &root; qlock(&srvlk);
rlock(b); for(sp = srv; sp != nil; sp = sp->link) {
for(sp = b->srv; sp != nil; sp = sp->link) {
if(sp->chan == c){ if(sp->chan == c){
s = malloc(3+strlen(sp->name)+1); s = malloc(3+strlen(sp->name)+1);
if(s != nil) if(s != nil)
@ -274,17 +103,15 @@ srvname(Chan *c)
break; break;
} }
} }
runlock(b); qunlock(&srvlk);
return s; return s;
} }
static Chan* static Chan*
srvopen(Chan *c, int omode) srvopen(Chan *c, int omode)
{ {
Board *b, *ch;
Srv *sp; Srv *sp;
Chan *nc; Chan *nc;
char buf[64];
if(c->qid.type == QTDIR){ if(c->qid.type == QTDIR){
if(omode & ORCLOSE) if(omode & ORCLOSE)
@ -296,53 +123,20 @@ srvopen(Chan *c, int omode)
c->offset = 0; c->offset = 0;
return c; return c;
} }
qlock(&srvlk);
if(waserror()){
qunlock(&srvlk);
nexterror();
}
sp = srvlookup(nil, c->qid.path);
if(sp == nil || sp->chan == nil)
error(Eshutdown);
if(omode&OTRUNC) if(omode&OTRUNC)
error(Eexist); error(Eexist);
if(omode&ORCLOSE) if(omode&ORCLOSE)
error(Eperm); error(Eperm);
b = c->aux;
if(NETTYPE(c->qid.path) == Qclone){;
wlock(b);
if(b->closed){
wunlock(b);
error(Eexpired);
}
ch = smalloc(sizeof *ch);
ch->qidpath = Qend;
ch->ref = 1;
do {
qlock(&boards);
ch->id = ++boards.path;
qunlock(&boards);
snprint(buf, sizeof buf, "%ld", ch->id);
} while(lookup(b->srv, buf, ~0UL) != nil);
ch->parent = b;
ch->path = b->qidpath++;
kstrdup(&ch->name, buf);
ch->link = b->child;
b->child = ch;
c->aux = ch;
c->qid.vers = ch->id;
c->qid.path = NETQID(ch->id, Qlease);
boardclunk(b, 0); //unlock
return c;
}
rlock(b);
if(waserror()){
runlock(b);
nexterror();
}
if(b->closed)
error(Eexpired);
sp = lookup(b->srv, nil, c->qid.path);
if(sp == nil || sp->chan == nil)
error(Eshutdown);
if(openmode(omode)!=sp->chan->mode && sp->chan->mode!=ORDWR) if(openmode(omode)!=sp->chan->mode && sp->chan->mode!=ORDWR)
error(Eperm); error(Eperm);
devpermcheck(sp->owner, sp->perm, omode); devpermcheck(sp->owner, sp->perm, omode);
@ -350,7 +144,7 @@ srvopen(Chan *c, int omode)
nc = sp->chan; nc = sp->chan;
incref(nc); incref(nc);
runlock(b); qunlock(&srvlk);
poperror(); poperror();
cclose(c); cclose(c);
@ -360,7 +154,6 @@ srvopen(Chan *c, int omode)
static Chan* static Chan*
srvcreate(Chan *c, char *name, int omode, ulong perm) srvcreate(Chan *c, char *name, int omode, ulong perm)
{ {
Board *b;
Srv *sp; Srv *sp;
if(openmode(omode) != OWRITE) if(openmode(omode) != OWRITE)
@ -373,33 +166,27 @@ srvcreate(Chan *c, char *name, int omode, ulong perm)
kstrdup(&sp->name, name); kstrdup(&sp->name, name);
kstrdup(&sp->owner, up->user); kstrdup(&sp->owner, up->user);
b = c->aux; qlock(&srvlk);
wlock(b);
if(waserror()){ if(waserror()){
wunlock(b); qunlock(&srvlk);
free(sp->owner); free(sp->owner);
free(sp->name); free(sp->name);
free(sp); free(sp);
nexterror(); nexterror();
} }
if(b->closed) if(srvlookup(name, -1) != nil)
error(Eexpired);
if(lookup(b->srv, name, ~0UL) != nil)
error(Eexist);
if(lookup(b->child, name, ~0UL) != nil)
error(Eexist); error(Eexist);
sp->perm = perm&0777; sp->perm = perm&0777;
sp->path = b->qidpath++; sp->path = qidpath++;
c->qid.path = NETQID(b->id, sp->path); c->qid.path = sp->path;
c->qid.vers = b->id;
c->qid.type = QTFILE; c->qid.type = QTFILE;
sp->link = b->srv; sp->link = srv;
b->srv = sp; srv = sp;
wunlock(b); qunlock(&srvlk);
poperror(); poperror();
c->flag |= COPEN; c->flag |= COPEN;
@ -411,24 +198,22 @@ srvcreate(Chan *c, char *name, int omode, ulong perm)
static void static void
srvremove(Chan *c) srvremove(Chan *c)
{ {
Board *b; Srv *sp, **l;
Srv *sp;
if(c->qid.type == QTDIR) if(c->qid.type == QTDIR)
error(Eperm); error(Eperm);
switch(NETTYPE(c->qid.path)){
case Qlease:
case Qclone:
error(Eperm);
}
b = c->aux; qlock(&srvlk);
wlock(b);
if(waserror()){ if(waserror()){
wunlock(b); qunlock(&srvlk);
nexterror(); nexterror();
} }
sp = lookup(b->srv, nil, c->qid.path); l = &srv;
for(sp = *l; sp != nil; sp = *l) {
if(sp->path == c->qid.path)
break;
l = &sp->link;
}
if(sp == nil) if(sp == nil)
error(Enonexist); error(Enonexist);
@ -444,9 +229,10 @@ srvremove(Chan *c)
if((sp->perm&7) != 7 && strcmp(sp->owner, up->user) && !iseve()) if((sp->perm&7) != 7 && strcmp(sp->owner, up->user) && !iseve())
error(Eperm); error(Eperm);
remove((Link**)&b->srv, nil, c->qid.path); *l = sp->link;
sp->link = nil;
boardclunk(b, 0); //unlock qunlock(&srvlk);
poperror(); poperror();
if(sp->chan != nil) if(sp->chan != nil)
@ -459,18 +245,12 @@ srvremove(Chan *c)
static int static int
srvwstat(Chan *c, uchar *dp, int n) srvwstat(Chan *c, uchar *dp, int n)
{ {
Board *b;
char *strs; char *strs;
Srv *sp; Srv *sp;
Dir d; Dir d;
if(c->qid.type & QTDIR) if(c->qid.type & QTDIR)
error(Eperm); error(Eperm);
switch(NETTYPE(c->qid.path)){
case Qlease:
case Qclone:
error(Eperm);
}
strs = smalloc(n); strs = smalloc(n);
if(waserror()){ if(waserror()){
@ -481,16 +261,13 @@ srvwstat(Chan *c, uchar *dp, int n)
if(n == 0) if(n == 0)
error(Eshortstat); error(Eshortstat);
b = c->aux; qlock(&srvlk);
wlock(b);
if(waserror()){ if(waserror()){
wunlock(b); qunlock(&srvlk);
nexterror(); nexterror();
} }
if(b->closed)
error(Eexpired);
sp = lookup(b->srv, nil, c->qid.path); sp = srvlookup(nil, c->qid.path);
if(sp == nil) if(sp == nil)
error(Enonexist); error(Enonexist);
@ -502,10 +279,6 @@ srvwstat(Chan *c, uchar *dp, int n)
error(Ebadchar); error(Ebadchar);
if(strlen(d.name) >= sizeof(up->genbuf)) if(strlen(d.name) >= sizeof(up->genbuf))
error(Etoolong); error(Etoolong);
if(lookup(b->srv, d.name, ~0UL) != nil)
error(Eexist);
if(lookup(b->child, d.name, ~0UL) != nil)
error(Eexist);
kstrdup(&sp->name, d.name); kstrdup(&sp->name, d.name);
} }
if(d.uid != nil && *d.uid) if(d.uid != nil && *d.uid)
@ -513,7 +286,7 @@ srvwstat(Chan *c, uchar *dp, int n)
if(d.mode != ~0UL) if(d.mode != ~0UL)
sp->perm = d.mode & 0777; sp->perm = d.mode & 0777;
wunlock(b); qunlock(&srvlk);
poperror(); poperror();
free(strs); free(strs);
@ -525,47 +298,22 @@ srvwstat(Chan *c, uchar *dp, int n)
static void static void
srvclose(Chan *c) srvclose(Chan *c)
{ {
Board *b; /*
int expired; * in theory we need to override any changes in removability
* since open, but since all that's checked is the owner,
expired = 0; * which is immutable, all is well.
if(NETTYPE(c->qid.path) == Qlease) */
expired++; if(c->flag & CRCLOSE){
else if(c->flag & CRCLOSE){
/*
* in theory we need to override any changes in removability
* since open, but since all that's checked is the owner,
* which is immutable, all is well.
*/
if(waserror()) if(waserror())
goto Clunk; return;
srvremove(c); srvremove(c);
poperror(); poperror();
return;
} }
Clunk:
b = c->aux;
wlock(b);
boardclunk(b, expired); //unlock
} }
static long static long
srvread(Chan *c, void *va, long n, vlong off) srvread(Chan *c, void *va, long n, vlong)
{ {
Board *b;
if(NETTYPE(c->qid.path) == Qlease){
b = c->aux;
rlock(b);
if(waserror()){
runlock(b);
nexterror();
}
n = readstr((ulong)off, va, n, b->name);
runlock(b);
poperror();
return n;
}
isdir(c); isdir(c);
return devdirread(c, va, n, 0, 0, srvgen); return devdirread(c, va, n, 0, 0, srvgen);
} }
@ -573,15 +321,11 @@ srvread(Chan *c, void *va, long n, vlong off)
static long static long
srvwrite(Chan *c, void *va, long n, vlong) srvwrite(Chan *c, void *va, long n, vlong)
{ {
Board *b;
Srv *sp; Srv *sp;
Chan *c1; Chan *c1;
int fd; int fd;
char buf[32]; char buf[32];
if(NETTYPE(c->qid.path) == Qlease)
error(Eperm);
if(n >= sizeof buf) if(n >= sizeof buf)
error(Etoobig); error(Etoobig);
memmove(buf, va, n); /* so we can NUL-terminate */ memmove(buf, va, n); /* so we can NUL-terminate */
@ -590,18 +334,15 @@ srvwrite(Chan *c, void *va, long n, vlong)
c1 = fdtochan(fd, -1, 0, 1); /* error check and inc ref */ c1 = fdtochan(fd, -1, 0, 1); /* error check and inc ref */
b = c->aux; qlock(&srvlk);
wlock(b);
if(waserror()) { if(waserror()) {
wunlock(b); qunlock(&srvlk);
cclose(c1); cclose(c1);
nexterror(); nexterror();
} }
if(b->closed)
error(Eexpired);
if(c1->qid.type & QTAUTH) if(c1->qid.type & QTAUTH)
error("cannot post auth file in srv"); error("cannot post auth file in srv");
sp = lookup(b->srv, nil, c->qid.path); sp = srvlookup(nil, c->qid.path);
if(sp == nil) if(sp == nil)
error(Enonexist); error(Enonexist);
@ -610,7 +351,7 @@ srvwrite(Chan *c, void *va, long n, vlong)
sp->chan = c1; sp->chan = c1;
wunlock(b); qunlock(&srvlk);
poperror(); poperror();
return n; return n;
} }
@ -639,14 +380,12 @@ Dev srvdevtab = {
void void
srvrenameuser(char *old, char *new) srvrenameuser(char *old, char *new)
{ {
Board *b;
Srv *sp; Srv *sp;
b = &root; qlock(&srvlk);
wlock(b); for(sp = srv; sp != nil; sp = sp->link) {
for(sp = b->srv; sp != nil; sp = sp->link) {
if(sp->owner != nil && strcmp(old, sp->owner) == 0) if(sp->owner != nil && strcmp(old, sp->owner) == 0)
kstrdup(&sp->owner, new); kstrdup(&sp->owner, new);
} }
wunlock(b); qunlock(&srvlk);
} }

View file

@ -5,6 +5,8 @@
#include <bio.h> #include <bio.h>
uint messagesize = 65536; /* just a buffer size */ uint messagesize = 65536; /* just a buffer size */
int aflag;
int srvfd;
void void
usage(void) usage(void)
@ -37,22 +39,32 @@ connectcmd(char *cmd)
} }
} }
static int rendez;
void void
watch(int fd) watch(int fd)
{ {
int n; int n;
uchar *buf; uchar *buf;
Fcall f; Fcall f, *p;
buf = malloc(messagesize); buf = malloc(messagesize);
if(buf == nil) if(buf == nil)
sysfatal("out of memory"); sysfatal("out of memory");
while((n = read9pmsg(fd, buf, messagesize)) > 0){ while((n = read9pmsg(fd, buf, messagesize)) > 0){
memset(&f, 0, sizeof f);
if(convM2S(buf, n, &f) != n){ if(convM2S(buf, n, &f) != n){
print("convM2S: %r\n"); print("convM2S: %r\n");
continue; continue;
} }
if(aflag){
p = malloc(sizeof *p);
if(p == nil)
sysfatal("out of memory");
memmove(p, &f, sizeof f);
rendezvous(&rendez, p);
}
print("\t<- %F\n", &f); print("\t<- %F\n", &f);
} }
if(n == 0) if(n == 0)
@ -62,7 +74,7 @@ watch(int fd)
} }
char* char*
tversion(Fcall *f, int, char **argv) version(Fcall *f, int, char **argv)
{ {
f->msize = strtol(argv[0], 0, 0); f->msize = strtol(argv[0], 0, 0);
if(f->msize > messagesize) if(f->msize > messagesize)
@ -80,6 +92,58 @@ tauth(Fcall *f, int, char **argv)
return nil; return nil;
} }
char*
strtoqid(char *s, Qid *q)
{
char *dot;
int state;
char buf[1024];
char *p;
state = 0;
p = buf;
for(dot = s; *dot; dot++){
assert(p - buf < sizeof buf);
switch(*dot){
case '{':
continue;
default:
*p++ = *dot;
break;
case '}':
case ',':
*p = '\0';
switch(state){
case 0:
q->path = strtoull(buf, 0, 0);
break;
case 1:
q->vers = strtoul(buf, 0, 0);
break;
case 2:
if(buf[0] == 'f' || strcmp("QTFILE", buf) == 0)
q->type = QTFILE;
else if(buf[0] == 'd' || strcmp("QTDIR", buf) == 0)
q->type = QTDIR;
else
q->type = (uchar)strtol(buf, 0, 0);
break;
}
p = buf;
state++;
}
}
if(state != 3)
return "malformed qid";
return nil;
}
char*
rauth(Fcall *f, int, char **argv)
{
return strtoqid(argv[0], &f->aqid);
}
char* char*
tflush(Fcall *f, int, char **argv) tflush(Fcall *f, int, char **argv)
{ {
@ -97,6 +161,12 @@ tattach(Fcall *f, int, char **argv)
return nil; return nil;
} }
char*
rattach(Fcall *f, int, char **argv)
{
return strtoqid(argv[0], &f->qid);
}
char* char*
twalk(Fcall *f, int argc, char **argv) twalk(Fcall *f, int argc, char **argv)
{ {
@ -114,6 +184,24 @@ twalk(Fcall *f, int argc, char **argv)
return nil; return nil;
} }
char*
rwalk(Fcall *f, int argc, char **argv)
{
int i;
char *e;
if(argc >= MAXWELEM)
return "too many names";
f->nwqid = argc;
for(i = 0; i < argc; i++){
e = strtoqid(argv[i], &f->wqid[i]);
if(e != nil)
return e;
}
return nil;
}
char* char*
topen(Fcall *f, int, char **argv) topen(Fcall *f, int, char **argv)
{ {
@ -122,6 +210,13 @@ topen(Fcall *f, int, char **argv)
return nil; return nil;
} }
char*
ropen(Fcall *f, int, char **argv)
{
f->iounit = strtol(argv[1], 0, 0);
return strtoqid(argv[0], &f->qid);
}
char* char*
tcreate(Fcall *f, int, char **argv) tcreate(Fcall *f, int, char **argv)
{ {
@ -141,6 +236,14 @@ tread(Fcall *f, int, char **argv)
return nil; return nil;
} }
char*
rread(Fcall *f, int, char **argv)
{
f->data = argv[0];
f->count = strlen(argv[0]);
return nil;
}
char* char*
twrite(Fcall *f, int, char **argv) twrite(Fcall *f, int, char **argv)
{ {
@ -151,6 +254,13 @@ twrite(Fcall *f, int, char **argv)
return nil; return nil;
} }
char*
rwrite(Fcall *f, int, char **argv)
{
f->count = strtol(argv[0], 0, 0);
return nil;
}
char* char*
tclunk(Fcall *f, int, char **argv) tclunk(Fcall *f, int, char **argv)
{ {
@ -194,16 +304,21 @@ twstat(Fcall *f, int, char **argv)
static uchar buf[DIRMAX]; static uchar buf[DIRMAX];
Dir d; Dir d;
//We function as Rstat as well
if(f->type == Twstat){
f->fid = strtol(argv[0], 0, 0);
argv++;
}
memset(&d, 0, sizeof d); memset(&d, 0, sizeof d);
nulldir(&d); nulldir(&d);
d.name = argv[1]; d.name = argv[0];
d.uid = argv[2]; d.uid = argv[1];
d.gid = argv[3]; d.gid = argv[2];
d.mode = xstrtoul(argv[4]); d.mode = xstrtoul(argv[3]);
d.mtime = xstrtoul(argv[5]); d.mtime = xstrtoul(argv[4]);
d.length = xstrtoull(argv[6]); d.length = xstrtoull(argv[5]);
f->fid = strtol(argv[0], 0, 0);
f->stat = buf; f->stat = buf;
f->nstat = convD2M(&d, buf, sizeof buf); f->nstat = convD2M(&d, buf, sizeof buf);
if(f->nstat < BIT16SZ) if(f->nstat < BIT16SZ)
@ -212,6 +327,21 @@ twstat(Fcall *f, int, char **argv)
return nil; return nil;
} }
char*
nop(Fcall*, int, char**)
{
/* Rwstat,Rremove,Rclunk,Rflush */
return nil;
}
enum{
Xsource = Tmax+1,
Xdef,
Xend,
Xnexttag,
};
int taggen; int taggen;
char* char*
@ -224,6 +354,72 @@ settag(Fcall*, int, char **argv)
return buf; return buf;
} }
char* shell9p(int);
char*
source(Fcall*, int, char **argv)
{
int fd;
char *e;
fd = open(argv[0], OREAD);
if(fd < 0)
return smprint("^could not open %s: %r", argv[0]);
e = shell9p(fd);
close(fd);
return e;
}
typedef struct Func Func;
struct Func {
Func *link;
char *name;
char *lines[128];
int n;
};
Func *globals;
Func *local;
char*
funcdef(Fcall*, int, char **argv)
{
if(local != nil)
return smprint("^can not define func %s; %s not terminated", argv[0], local->name);
local = mallocz(sizeof *local, 1);
if(local == nil)
return "!out of memory";
local->name = strdup(argv[0]);
return nil;
}
char*
funcend(Fcall*, int, char**)
{
Func **l;
Func *p;
int i;
if(local == nil)
return "?no function defined";
l = &globals;
for(p = globals; p != nil; p = p->link){
if(strcmp(local->name, p->name) == 0)
break;
l = &p->link;
}
if(p != nil){
for(i=0; i<p->n; i++)
free(p->lines[i]);
free(p->name);
free(p);
}
*l = local;
local = nil;
return nil;
}
typedef struct Cmd Cmd; typedef struct Cmd Cmd;
struct Cmd { struct Cmd {
char *name; char *name;
@ -234,87 +430,184 @@ struct Cmd {
}; };
Cmd msg9p[] = { Cmd msg9p[] = {
"Tversion", Tversion, 2, "messagesize version", tversion, "Tversion", Tversion, 2, "messagesize version", version,
"Rversion", Rversion, 2, "messagesize version", version,
"Tauth", Tauth, 3, "afid uname aname", tauth, "Tauth", Tauth, 3, "afid uname aname", tauth,
"Rauth", Rauth, 1, "aqid", rauth,
"Tflush", Tflush, 1, "oldtag", tflush, "Tflush", Tflush, 1, "oldtag", tflush,
"Rflush", Rflush, 0, "", nop,
"Tattach", Tattach, 4, "fid afid uname aname", tattach, "Tattach", Tattach, 4, "fid afid uname aname", tattach,
"Rattach", Rattach, 1, "qid", rattach,
"Twalk", Twalk, 0, "fid newfid [name...]", twalk, "Twalk", Twalk, 0, "fid newfid [name...]", twalk,
"Rwalk", Rwalk, 0, "name...", rwalk,
"Topen", Topen, 2, "fid mode", topen, "Topen", Topen, 2, "fid mode", topen,
"Ropen", Ropen, 2, "qid iounit", ropen,
"Tcreate", Tcreate, 4, "fid name perm mode", tcreate, "Tcreate", Tcreate, 4, "fid name perm mode", tcreate,
"Rcreate", Rcreate, 2, "qid iounit", ropen,
"Tread", Tread, 3, "fid offset count", tread, "Tread", Tread, 3, "fid offset count", tread,
"Rread", Rread, 1, "data", rread,
"Twrite", Twrite, 3, "fid offset data", twrite, "Twrite", Twrite, 3, "fid offset data", twrite,
"Rwrite", Rwrite, 1, "count", rwrite,
"Tclunk", Tclunk, 1, "fid", tclunk, "Tclunk", Tclunk, 1, "fid", tclunk,
"Rclunk", Rclunk, 0, "", nop,
"Tremove", Tremove, 1, "fid", tremove, "Tremove", Tremove, 1, "fid", tremove,
"Rremove", Rremove, 0, "", nop,
"Tstat", Tstat, 1, "fid", tstat, "Tstat", Tstat, 1, "fid", tstat,
"Rstat", Rstat, 6, "name uid gid mode mtime length", twstat,
"Twstat", Twstat, 7, "fid name uid gid mode mtime length", twstat, "Twstat", Twstat, 7, "fid name uid gid mode mtime length", twstat,
"nexttag", 0, 0, "", settag, "Rwstat", Rwstat, 0, "", nop,
".", Xsource, 1, "file", source,
"def", Xdef, 1, "name", funcdef,
"end", Xend, 0, "", funcend,
"nexttag", Xnexttag, 0, "", settag,
}; };
void char*
run(char *p)
{
char *e, *f[10];
int i, n, nf, n2;
Fcall t, *r;
Func *func;
char *cp;
static uchar *buf = nil;
static uchar *buf2 = nil;
if(buf == nil)
buf = malloc(messagesize);
if(buf2 == nil)
buf2 = malloc(messagesize);
if(buf == nil || buf2 == nil)
return "!out of memory";
if(p[0] == '#')
return nil;
if(local != nil && strstr(p, "end") == nil){
local->lines[local->n++] = strdup(p);
return nil;
}
if((nf = tokenize(p, f, nelem(f))) == 0)
return nil;
for(i=0; i<nelem(msg9p); i++)
if(strcmp(f[0], msg9p[i].name) == 0)
break;
if(i == nelem(msg9p)){
if(local != nil)
return "?unknown message";
for(func = globals; func != nil; func = func->link){
if(strcmp(func->name, f[0]) != 0)
continue;
for(i = 0; i < func->n; i++){
cp = strdup(func->lines[i]);
if(e = run(cp)){
free(cp);
return e;
}
free(cp);
}
return nil;
}
return "?unknown message";
}
memset(&t, 0, sizeof t);
t.type = msg9p[i].type;
if(t.type == Tversion)
t.tag = NOTAG;
else
t.tag = ++taggen;
if(nf < 1 || (msg9p[i].argc && nf != 1+msg9p[i].argc))
return smprint("^usage: %s %s", msg9p[i].name, msg9p[i].usage);
if((e = msg9p[i].fn(&t, nf-1, f+1)) || t.type > Tmax)
return e;
n = convS2M(&t, buf, messagesize);
if(n <= BIT16SZ)
return "?message too large for buffer";
switch(msg9p[i].name[0]){
case 'R':
if(!aflag)
break;
r = rendezvous(&rendez, nil);
r->tag = t.tag;
n2 = convS2M(r, buf2, messagesize);
if(n != n2 || memcmp(buf, buf2, n) != 0){
fprint(2, "?mismatch %F != %F\n", r, &t);
return "!assert fail";
}
free(r);
break;
case 'T':
if(write(srvfd, buf, n) != n)
return "!write fails";
print("\t-> %F\n", &t);
}
return nil;
}
char*
shell9p(int fd) shell9p(int fd)
{ {
char *e, *f[10], *p; char *e, *p;
uchar *buf;
int i, n, nf;
Biobuf b; Biobuf b;
Fcall t;
buf = malloc(messagesize); Binit(&b, fd, OREAD);
if(buf == nil){
fprint(2, "out of memory\n");
return;
}
taggen = 0;
Binit(&b, 0, OREAD);
while(p = Brdline(&b, '\n')){ while(p = Brdline(&b, '\n')){
p[Blinelen(&b)-1] = '\0'; p[Blinelen(&b)-1] = '\0';
if(p[0] == '#') e = run(p);
if(e == nil)
continue; continue;
if((nf = tokenize(p, f, nelem(f))) == 0) switch(*e){
continue; case 0:
for(i=0; i<nelem(msg9p); i++)
if(strcmp(f[0], msg9p[i].name) == 0)
break;
if(i == nelem(msg9p)){
fprint(2, "?unknown message\n");
continue;
}
memset(&t, 0, sizeof t);
t.type = msg9p[i].type;
if(t.type == Tversion)
t.tag = NOTAG;
else
t.tag = ++taggen;
if(nf < 1 || (msg9p[i].argc && nf != 1+msg9p[i].argc)){
fprint(2, "?usage: %s %s\n", msg9p[i].name, msg9p[i].usage);
continue;
}
if(e = msg9p[i].fn(&t, nf-1, f+1)){
fprint(2, "?%s\n", e);
continue;
}
n = convS2M(&t, buf, messagesize);
if(n <= BIT16SZ){
fprint(2, "?message too large for buffer\n");
continue;
}
if(write(fd, buf, n) != n){
fprint(2, "?write fails: %r\n");
break; break;
case '?':
default:
fprint(2, "%s\n", e);
break;
case '^':
e[0] = '?';
fprint(2, "%s\n", e);
free(e);
break;
case '!':
Bterm(&b);
return e;
} }
print("\t-> %F\n", &t);
} }
Bterm(&b);
return nil;
} }
void void
main(int argc, char **argv) main(int argc, char **argv)
{ {
int fd, pid, cmd, net; int pid, cmd, net;
char *status;
cmd = 0; cmd = 0;
net = 0; net = 0;
aflag = 0;
taggen = 0;
ARGBEGIN{ ARGBEGIN{
case 'a':
aflag = 1;
break;
case 'c': case 'c':
cmd = 1; cmd = 1;
break; break;
@ -339,29 +632,30 @@ main(int argc, char **argv)
usage(); usage();
if(cmd) if(cmd)
fd = connectcmd(argv[0]); srvfd = connectcmd(argv[0]);
else if(net){ else if(net){
fd = dial(netmkaddr(argv[0], "net", "9fs"), 0, 0, 0); srvfd = dial(netmkaddr(argv[0], "net", "9fs"), 0, 0, 0);
if(fd < 0) if(srvfd < 0)
sysfatal("dial: %r"); sysfatal("dial: %r");
}else{ }else{
fd = open(argv[0], ORDWR); srvfd = open(argv[0], ORDWR);
if(fd < 0) if(srvfd < 0)
sysfatal("open: %r"); sysfatal("open: %r");
} }
status = nil;
switch(pid = rfork(RFPROC|RFMEM)){ switch(pid = rfork(RFPROC|RFMEM)){
case -1: case -1:
sysfatal("rfork: %r"); sysfatal("rfork: %r");
break; break;
case 0: case 0:
watch(fd); watch(srvfd);
postnote(PNPROC, getppid(), "kill"); postnote(PNPROC, getppid(), "kill");
break; break;
default: default:
shell9p(fd); status = shell9p(0);
postnote(PNPROC, pid, "kill"); postnote(PNPROC, pid, "kill");
break; break;
} }
exits(nil); exits(status);
} }

View file

@ -45,7 +45,7 @@ struct Ptprpc
uchar type[2]; uchar type[2];
uchar code[2]; uchar code[2];
uchar transid[4]; uchar transid[4];
uchar d[500]; uchar d[1012];
}; };
struct Node struct Node

View file

@ -214,6 +214,7 @@ void
main(int argc, char **argv) main(int argc, char **argv)
{ {
char *s, *mode; char *s, *mode;
char *mtpt;
int stdio; int stdio;
s = nil; s = nil;
@ -241,7 +242,13 @@ main(int argc, char **argv)
usage(); usage();
if(stdio == 0){ if(stdio == 0){
postmountsrv(&fs, s, argc ? argv[0] : "/mnt/skel", MREPL); if(s != nil && argc == 0)
mtpt = nil;
else if(argc)
mtpt = argv[0];
else
mtpt = "/mnt/skel";
postmountsrv(&fs, s, mtpt, MREPL);
exits(nil); exits(nil);
} }
fs.infd = 0; fs.infd = 0;

View file

@ -387,7 +387,7 @@ lower(char *s)
} }
int int
spfquery(Squery *x, char *d, int include) spfquery(Squery *x, char *d, int include, int depth)
{ {
char *s, **t, *r, *p, *q, buf[10]; char *s, **t, *r, *p, *q, buf[10];
int i, n, c; int i, n, c;
@ -398,6 +398,10 @@ spfquery(Squery *x, char *d, int include)
fprint(2, "spf: include loop: %s (%s)\n", d, inc->s); fprint(2, "spf: include loop: %s (%s)\n", d, inc->s);
return -1; return -1;
} }
if(depth >= 10){
fprint(2, "spf: too much recursion %s\n", d);
return -1;
}
s = spffetch(x, d); s = spffetch(x, d);
if(!s) if(!s)
return -1; return -1;
@ -457,7 +461,7 @@ spfquery(Squery *x, char *d, int include)
if(rflag) if(rflag)
fprint(2, "I> %s\n", q); fprint(2, "I> %s\n", q);
addbegin(mod, r, q); addbegin(mod, r, q);
if(spfquery(x, q, 1) == -1){ if(spfquery(x, q, 1, depth+1) == -1){
ditch(); ditch();
addfail(); addfail();
}else }else
@ -704,7 +708,7 @@ main(int argc, char **argv)
goto loop; goto loop;
spfinit(&q, d, argc, argv); /* or s? */ spfinit(&q, d, argc, argv); /* or s? */
addbegin('+', ".", s); addbegin('+', ".", s);
if(spfquery(&q, s, 0) != -1) if(spfquery(&q, s, 0, 0) != -1)
break; break;
} }
if(eflag && nspf) if(eflag && nspf)