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
.B bind #s /srv
.BI #s/ clone
.BI #s/ n
.BI #s/ service1
.BI #s/ service2
...
@ -14,7 +12,7 @@ srv \- server registry
.SH DESCRIPTION
The
.I srv
device provides a tree of directories holding
device provides a one-level directory holding
already-open channels to services.
In effect,
.I srv
@ -42,18 +40,6 @@ releases that reference.
.PP
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.
.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
To drop one end of a pipe into
.BR /srv ,

View file

@ -5,249 +5,80 @@
#include "fns.h"
#include "../port/error.h"
#include "netif.h"
typedef struct Link Link;
struct Link
{
void *link;
char *name;
ulong path;
};
typedef struct Srv Srv;
struct Srv
{
Link;
char *name;
char *owner;
ulong perm;
Chan *chan;
Srv *link;
ulong path;
};
typedef struct Board Board;
struct Board
static QLock srvlk;
static Srv *srv;
static int qidpath;
static Srv*
srvlookup(char *name, ulong qidpath)
{
Link;
RWlock;
Ref;
Srv *sp;
Board *parent;
Board *child;
Srv *srv;
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;
for(sp = srv; sp != nil; sp = sp->link) {
if(sp->path == qidpath || (name != nil && strcmp(sp->name, name) == 0))
return sp;
}
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
srvgen(Chan *c, char *name, Dirtab*, int, int s, Dir *dp)
{
Srv *sp;
Board *b, *ch;
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){
ch = b->parent;
if(ch == nil)
ch = &root;
goto Child;
devdir(c, c->qid, "#s", 0, eve, 0555, dp);
return 1;
}
if(name != nil){
if(strcmp("clone", name) == 0)
goto Clone;
sp = lookup(b->srv, name, ~0UL);
if(sp == nil)
ch = lookup(b->child, name, ~0UL);
} else {
if(s == 0)
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)
qlock(&srvlk);
if(name != nil)
sp = srvlookup(name, -1);
else {
for(sp = srv; sp != nil && s > 0; sp = sp->link)
s--;
}
if(sp != nil){
kstrcpy(up->genbuf, sp->name, sizeof up->genbuf);
q.vers = NETID(c->qid.path);
q.path = NETQID(q.vers, sp->path);
devdir(c, q, up->genbuf, 0, sp->owner, sp->perm, dp);
} else if(ch != nil){
Child:
kstrcpy(up->genbuf, ch->name, sizeof up->genbuf);
q.vers = ch->id;
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();
if(sp == nil || (name != nil && (strlen(sp->name) >= sizeof(up->genbuf)))) {
qunlock(&srvlk);
return -1;
}
mkqid(&q, sp->path, 0, QTFILE);
/* make sure name string continues to exist after we release lock */
kstrcpy(up->genbuf, sp->name, sizeof up->genbuf);
devdir(c, q, up->genbuf, 0, sp->owner, sp->perm, dp);
qunlock(&srvlk);
return 1;
}
static void
srvinit(void)
{
root.qidpath = Qend;
root.name = "#s";
qidpath = 1;
}
static Chan*
srvattach(char *spec)
{
Chan *c;
c = devattach('s', spec);
c->aux = &root;
return c;
return devattach('s', spec);
}
static Walkqid*
srvwalk(Chan *c, Chan *nc, char **name, int nname)
{
Board *b;
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;
return devwalk(c, nc, name, nname, 0, 0, srvgen);
}
static int
@ -259,14 +90,12 @@ srvstat(Chan *c, uchar *db, int n)
char*
srvname(Chan *c)
{
Board *b;
Srv *sp;
char *s;
s = nil;
b = &root;
rlock(b);
for(sp = b->srv; sp != nil; sp = sp->link) {
qlock(&srvlk);
for(sp = srv; sp != nil; sp = sp->link) {
if(sp->chan == c){
s = malloc(3+strlen(sp->name)+1);
if(s != nil)
@ -274,17 +103,15 @@ srvname(Chan *c)
break;
}
}
runlock(b);
qunlock(&srvlk);
return s;
}
static Chan*
srvopen(Chan *c, int omode)
{
Board *b, *ch;
Srv *sp;
Chan *nc;
char buf[64];
if(c->qid.type == QTDIR){
if(omode & ORCLOSE)
@ -296,53 +123,20 @@ srvopen(Chan *c, int omode)
c->offset = 0;
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)
error(Eexist);
if(omode&ORCLOSE)
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)
error(Eperm);
devpermcheck(sp->owner, sp->perm, omode);
@ -350,7 +144,7 @@ srvopen(Chan *c, int omode)
nc = sp->chan;
incref(nc);
runlock(b);
qunlock(&srvlk);
poperror();
cclose(c);
@ -360,7 +154,6 @@ srvopen(Chan *c, int omode)
static Chan*
srvcreate(Chan *c, char *name, int omode, ulong perm)
{
Board *b;
Srv *sp;
if(openmode(omode) != OWRITE)
@ -373,33 +166,27 @@ srvcreate(Chan *c, char *name, int omode, ulong perm)
kstrdup(&sp->name, name);
kstrdup(&sp->owner, up->user);
b = c->aux;
wlock(b);
qlock(&srvlk);
if(waserror()){
wunlock(b);
qunlock(&srvlk);
free(sp->owner);
free(sp->name);
free(sp);
nexterror();
}
if(b->closed)
error(Eexpired);
if(lookup(b->srv, name, ~0UL) != nil)
error(Eexist);
if(lookup(b->child, name, ~0UL) != nil)
if(srvlookup(name, -1) != nil)
error(Eexist);
sp->perm = perm&0777;
sp->path = b->qidpath++;
sp->path = qidpath++;
c->qid.path = NETQID(b->id, sp->path);
c->qid.vers = b->id;
c->qid.path = sp->path;
c->qid.type = QTFILE;
sp->link = b->srv;
b->srv = sp;
sp->link = srv;
srv = sp;
wunlock(b);
qunlock(&srvlk);
poperror();
c->flag |= COPEN;
@ -411,24 +198,22 @@ srvcreate(Chan *c, char *name, int omode, ulong perm)
static void
srvremove(Chan *c)
{
Board *b;
Srv *sp;
Srv *sp, **l;
if(c->qid.type == QTDIR)
error(Eperm);
switch(NETTYPE(c->qid.path)){
case Qlease:
case Qclone:
error(Eperm);
}
b = c->aux;
wlock(b);
qlock(&srvlk);
if(waserror()){
wunlock(b);
qunlock(&srvlk);
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)
error(Enonexist);
@ -444,9 +229,10 @@ srvremove(Chan *c)
if((sp->perm&7) != 7 && strcmp(sp->owner, up->user) && !iseve())
error(Eperm);
remove((Link**)&b->srv, nil, c->qid.path);
*l = sp->link;
sp->link = nil;
boardclunk(b, 0); //unlock
qunlock(&srvlk);
poperror();
if(sp->chan != nil)
@ -459,18 +245,12 @@ srvremove(Chan *c)
static int
srvwstat(Chan *c, uchar *dp, int n)
{
Board *b;
char *strs;
Srv *sp;
Dir d;
if(c->qid.type & QTDIR)
error(Eperm);
switch(NETTYPE(c->qid.path)){
case Qlease:
case Qclone:
error(Eperm);
}
strs = smalloc(n);
if(waserror()){
@ -481,16 +261,13 @@ srvwstat(Chan *c, uchar *dp, int n)
if(n == 0)
error(Eshortstat);
b = c->aux;
wlock(b);
qlock(&srvlk);
if(waserror()){
wunlock(b);
qunlock(&srvlk);
nexterror();
}
if(b->closed)
error(Eexpired);
sp = lookup(b->srv, nil, c->qid.path);
sp = srvlookup(nil, c->qid.path);
if(sp == nil)
error(Enonexist);
@ -502,10 +279,6 @@ srvwstat(Chan *c, uchar *dp, int n)
error(Ebadchar);
if(strlen(d.name) >= sizeof(up->genbuf))
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);
}
if(d.uid != nil && *d.uid)
@ -513,7 +286,7 @@ srvwstat(Chan *c, uchar *dp, int n)
if(d.mode != ~0UL)
sp->perm = d.mode & 0777;
wunlock(b);
qunlock(&srvlk);
poperror();
free(strs);
@ -525,47 +298,22 @@ srvwstat(Chan *c, uchar *dp, int n)
static void
srvclose(Chan *c)
{
Board *b;
int expired;
expired = 0;
if(NETTYPE(c->qid.path) == Qlease)
expired++;
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.
*/
/*
* 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(c->flag & CRCLOSE){
if(waserror())
goto Clunk;
return;
srvremove(c);
poperror();
return;
}
Clunk:
b = c->aux;
wlock(b);
boardclunk(b, expired); //unlock
}
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);
return devdirread(c, va, n, 0, 0, srvgen);
}
@ -573,15 +321,11 @@ srvread(Chan *c, void *va, long n, vlong off)
static long
srvwrite(Chan *c, void *va, long n, vlong)
{
Board *b;
Srv *sp;
Chan *c1;
int fd;
char buf[32];
if(NETTYPE(c->qid.path) == Qlease)
error(Eperm);
if(n >= sizeof buf)
error(Etoobig);
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 */
b = c->aux;
wlock(b);
qlock(&srvlk);
if(waserror()) {
wunlock(b);
qunlock(&srvlk);
cclose(c1);
nexterror();
}
if(b->closed)
error(Eexpired);
if(c1->qid.type & QTAUTH)
error("cannot post auth file in srv");
sp = lookup(b->srv, nil, c->qid.path);
sp = srvlookup(nil, c->qid.path);
if(sp == nil)
error(Enonexist);
@ -610,7 +351,7 @@ srvwrite(Chan *c, void *va, long n, vlong)
sp->chan = c1;
wunlock(b);
qunlock(&srvlk);
poperror();
return n;
}
@ -639,14 +380,12 @@ Dev srvdevtab = {
void
srvrenameuser(char *old, char *new)
{
Board *b;
Srv *sp;
b = &root;
wlock(b);
for(sp = b->srv; sp != nil; sp = sp->link) {
qlock(&srvlk);
for(sp = srv; sp != nil; sp = sp->link) {
if(sp->owner != nil && strcmp(old, sp->owner) == 0)
kstrdup(&sp->owner, new);
}
wunlock(b);
qunlock(&srvlk);
}

View file

@ -5,6 +5,8 @@
#include <bio.h>
uint messagesize = 65536; /* just a buffer size */
int aflag;
int srvfd;
void
usage(void)
@ -37,22 +39,32 @@ connectcmd(char *cmd)
}
}
static int rendez;
void
watch(int fd)
{
int n;
uchar *buf;
Fcall f;
Fcall f, *p;
buf = malloc(messagesize);
if(buf == nil)
sysfatal("out of memory");
while((n = read9pmsg(fd, buf, messagesize)) > 0){
memset(&f, 0, sizeof f);
if(convM2S(buf, n, &f) != n){
print("convM2S: %r\n");
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);
}
if(n == 0)
@ -62,7 +74,7 @@ watch(int fd)
}
char*
tversion(Fcall *f, int, char **argv)
version(Fcall *f, int, char **argv)
{
f->msize = strtol(argv[0], 0, 0);
if(f->msize > messagesize)
@ -80,6 +92,58 @@ tauth(Fcall *f, int, char **argv)
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*
tflush(Fcall *f, int, char **argv)
{
@ -97,6 +161,12 @@ tattach(Fcall *f, int, char **argv)
return nil;
}
char*
rattach(Fcall *f, int, char **argv)
{
return strtoqid(argv[0], &f->qid);
}
char*
twalk(Fcall *f, int argc, char **argv)
{
@ -114,6 +184,24 @@ twalk(Fcall *f, int argc, char **argv)
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*
topen(Fcall *f, int, char **argv)
{
@ -122,6 +210,13 @@ topen(Fcall *f, int, char **argv)
return nil;
}
char*
ropen(Fcall *f, int, char **argv)
{
f->iounit = strtol(argv[1], 0, 0);
return strtoqid(argv[0], &f->qid);
}
char*
tcreate(Fcall *f, int, char **argv)
{
@ -141,6 +236,14 @@ tread(Fcall *f, int, char **argv)
return nil;
}
char*
rread(Fcall *f, int, char **argv)
{
f->data = argv[0];
f->count = strlen(argv[0]);
return nil;
}
char*
twrite(Fcall *f, int, char **argv)
{
@ -151,6 +254,13 @@ twrite(Fcall *f, int, char **argv)
return nil;
}
char*
rwrite(Fcall *f, int, char **argv)
{
f->count = strtol(argv[0], 0, 0);
return nil;
}
char*
tclunk(Fcall *f, int, char **argv)
{
@ -194,16 +304,21 @@ twstat(Fcall *f, int, char **argv)
static uchar buf[DIRMAX];
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);
nulldir(&d);
d.name = argv[1];
d.uid = argv[2];
d.gid = argv[3];
d.mode = xstrtoul(argv[4]);
d.mtime = xstrtoul(argv[5]);
d.length = xstrtoull(argv[6]);
d.name = argv[0];
d.uid = argv[1];
d.gid = argv[2];
d.mode = xstrtoul(argv[3]);
d.mtime = xstrtoul(argv[4]);
d.length = xstrtoull(argv[5]);
f->fid = strtol(argv[0], 0, 0);
f->stat = buf;
f->nstat = convD2M(&d, buf, sizeof buf);
if(f->nstat < BIT16SZ)
@ -212,6 +327,21 @@ twstat(Fcall *f, int, char **argv)
return nil;
}
char*
nop(Fcall*, int, char**)
{
/* Rwstat,Rremove,Rclunk,Rflush */
return nil;
}
enum{
Xsource = Tmax+1,
Xdef,
Xend,
Xnexttag,
};
int taggen;
char*
@ -224,6 +354,72 @@ settag(Fcall*, int, char **argv)
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;
struct Cmd {
char *name;
@ -234,87 +430,184 @@ struct Cmd {
};
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,
"Rauth", Rauth, 1, "aqid", rauth,
"Tflush", Tflush, 1, "oldtag", tflush,
"Rflush", Rflush, 0, "", nop,
"Tattach", Tattach, 4, "fid afid uname aname", tattach,
"Rattach", Rattach, 1, "qid", rattach,
"Twalk", Twalk, 0, "fid newfid [name...]", twalk,
"Rwalk", Rwalk, 0, "name...", rwalk,
"Topen", Topen, 2, "fid mode", topen,
"Ropen", Ropen, 2, "qid iounit", ropen,
"Tcreate", Tcreate, 4, "fid name perm mode", tcreate,
"Rcreate", Rcreate, 2, "qid iounit", ropen,
"Tread", Tread, 3, "fid offset count", tread,
"Rread", Rread, 1, "data", rread,
"Twrite", Twrite, 3, "fid offset data", twrite,
"Rwrite", Rwrite, 1, "count", rwrite,
"Tclunk", Tclunk, 1, "fid", tclunk,
"Rclunk", Rclunk, 0, "", nop,
"Tremove", Tremove, 1, "fid", tremove,
"Rremove", Rremove, 0, "", nop,
"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,
"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)
{
char *e, *f[10], *p;
uchar *buf;
int i, n, nf;
char *e, *p;
Biobuf b;
Fcall t;
buf = malloc(messagesize);
if(buf == nil){
fprint(2, "out of memory\n");
return;
}
taggen = 0;
Binit(&b, 0, OREAD);
Binit(&b, fd, OREAD);
while(p = Brdline(&b, '\n')){
p[Blinelen(&b)-1] = '\0';
if(p[0] == '#')
e = run(p);
if(e == nil)
continue;
if((nf = tokenize(p, f, nelem(f))) == 0)
continue;
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");
switch(*e){
case 0:
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
main(int argc, char **argv)
{
int fd, pid, cmd, net;
int pid, cmd, net;
char *status;
cmd = 0;
net = 0;
aflag = 0;
taggen = 0;
ARGBEGIN{
case 'a':
aflag = 1;
break;
case 'c':
cmd = 1;
break;
@ -339,29 +632,30 @@ main(int argc, char **argv)
usage();
if(cmd)
fd = connectcmd(argv[0]);
srvfd = connectcmd(argv[0]);
else if(net){
fd = dial(netmkaddr(argv[0], "net", "9fs"), 0, 0, 0);
if(fd < 0)
srvfd = dial(netmkaddr(argv[0], "net", "9fs"), 0, 0, 0);
if(srvfd < 0)
sysfatal("dial: %r");
}else{
fd = open(argv[0], ORDWR);
if(fd < 0)
srvfd = open(argv[0], ORDWR);
if(srvfd < 0)
sysfatal("open: %r");
}
status = nil;
switch(pid = rfork(RFPROC|RFMEM)){
case -1:
sysfatal("rfork: %r");
break;
case 0:
watch(fd);
watch(srvfd);
postnote(PNPROC, getppid(), "kill");
break;
default:
shell9p(fd);
status = shell9p(0);
postnote(PNPROC, pid, "kill");
break;
}
exits(nil);
exits(status);
}

View file

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

View file

@ -214,6 +214,7 @@ void
main(int argc, char **argv)
{
char *s, *mode;
char *mtpt;
int stdio;
s = nil;
@ -241,7 +242,13 @@ main(int argc, char **argv)
usage();
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);
}
fs.infd = 0;

View file

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