add srv -a option

This commit is contained in:
rsc 2005-03-21 17:24:21 +00:00
parent b8c9f31785
commit 5c84c448b8
4 changed files with 470 additions and 24 deletions

View file

@ -4,7 +4,16 @@
.SH SYNOPSIS
.B 9pserve
[
.B -v
.B -lv
]
[
.B -A
.I aname
.I afid
]
[
.B -M
.I msize
]
.I addr
.SH DESCRIPTION
@ -39,6 +48,33 @@ and clunks any outstanding fids belonging to the client.
is typically not invoked directly; use
.IR post9pservice (3)
instead.
.PP
The options are:
.TP
.B -l
logging; write a debugging log to
.IB addr .log \fR.
.TP
.B -v
verbose; more verbose when repeated
.TP
.B -A
rewrite all attach messages to use
.I aname
and
.IR afid ;
used to implement
.IR srv (4)'s
.B -a
option
.TP
.B -M
do not initialize the connection with a
.B Tversion
message;
instead assume 9P2000 and a maximum message size of
.IR msize
.PD
.SH "SEE ALSO
.IR intro (4),
.IR intro (9p)

View file

@ -3,6 +3,13 @@
srv, 9fs \- start network file esrvice
.SH SYNOPSIS
.B srv
[
.B -a
]
[
.B -k
.I keypattern
]
.I address
[
.I srvname
@ -22,6 +29,23 @@ as
.IR address ).
.PP
The
.B -a
option causes
.I srv
to post a pre-authenticated connection to the file system
.I aname
(by default, the empty string;
see
.IR attach (9p)).
.I Srv
authenticates over the 9P connection to establish a valid auth fid.
.IR Keypattern ,
if specified, is used to select the key used for authentication.
Client attach requests are rewritten to use the specified
.I aname
and auth fid.
.PP
The
.I 9fs
command executes the
.I srv

View file

@ -69,6 +69,7 @@ struct Conn
Queue *inq;
};
char *xaname;
char *addr;
int afd;
char adir[40];
@ -78,6 +79,9 @@ Queue *inq;
int verbose = 0;
int logging = 0;
int msize = 8192;
int xafid = NOFID;
int attached;
int versioned;
void *gethash(Hash**, uint);
int puthash(Hash**, uint, void*);
@ -104,6 +108,7 @@ void listenthread(void*);
void outputthread(void*);
void inputthread(void*);
void rewritehdr(Fcall*, uchar*);
void repack(Fcall*, uchar**);
int tlisten(char*, char*);
int taccept(int, char*);
int iolisten(Ioproc*, char*, char*);
@ -113,11 +118,12 @@ int iosendfd(Ioproc*, int, int);
void mainproc(void*);
int ignorepipe(void*, char*);
int timefmt(Fmt*);
void dorootstat(void);
void
usage(void)
{
fprint(2, "usage: 9pserve [-lv] address\n");
fprint(2, "usage: 9pserve [-lv] [-A aname afid] [-M msize] address\n");
fprint(2, "\treads/writes 9P messages on stdin/stdout\n");
threadexitsall("usage");
}
@ -131,21 +137,37 @@ threadmain(int argc, char **argv)
int fd;
x = getenv("verbose9pserve");
if(x)
if(x){
verbose = atoi(x);
fprint(2, "verbose9pserve %s => %d\n", x, verbose);
}
ARGBEGIN{
default:
usage();
case 'A':
attached = 1;
xaname = EARGF(usage());
xafid = atoi(EARGF(usage()));
break;
case 'M':
versioned = 1;
msize = atoi(EARGF(usage()));
break;
case 'v':
verbose++;
break;
case 'u':
isunix = 1;
isunix++;
break;
case 'l':
logging++;
break;
}ARGEND
if(attached && !versioned){
fprint(2, "-A must be used with -M\n");
usage();
}
if(argc != 1)
usage();
@ -187,24 +209,30 @@ mainproc(void *v)
outq = qalloc();
inq = qalloc();
f.type = Tversion;
f.version = "9P2000";
f.msize = msize;
f.tag = NOTAG;
n = convS2M(&f, vbuf, sizeof vbuf);
if(verbose > 1) fprint(2, "%T * <- %F\n", &f);
nn = write(1, vbuf, n);
if(n != nn)
sysfatal("error writing Tversion: %r\n");
n = read9pmsg(0, vbuf, sizeof vbuf);
if(convM2S(vbuf, n, &f) != n)
sysfatal("convM2S failure");
if(f.msize < msize)
msize = f.msize;
if(verbose > 1) fprint(2, "%T * -> %F\n", &f);
if(!versioned){
f.type = Tversion;
f.version = "9P2000";
f.msize = msize;
f.tag = NOTAG;
n = convS2M(&f, vbuf, sizeof vbuf);
if(verbose > 1) fprint(2, "%T * <- %F\n", &f);
nn = write(1, vbuf, n);
if(n != nn)
sysfatal("error writing Tversion: %r\n");
n = read9pmsg(0, vbuf, sizeof vbuf);
if(convM2S(vbuf, n, &f) != n)
sysfatal("convM2S failure");
if(f.msize < msize)
msize = f.msize;
if(verbose > 1) fprint(2, "%T * -> %F\n", &f);
}
threadcreate(inputthread, nil, STACK);
threadcreate(outputthread, nil, STACK);
// if(rootfid)
// dorootstat();
threadcreate(listenthread, nil, STACK);
threadexits(0);
}
@ -283,6 +311,16 @@ err(Msg *m, char *ename)
send9pmsg(m);
}
char*
estrdup(char *s)
{
char *t;
t = emalloc(strlen(s)+1);
strcpy(t, s);
return t;
}
void
connthread(void *arg)
{
@ -349,6 +387,18 @@ connthread(void *arg)
continue;
}
m->fid->ref++;
if(attached && m->afid==nil){
if(m->tx.aname[0] && strcmp(xaname, m->tx.aname) != 0){
err(m, "invalid attach name");
continue;
}
m->tx.afid = xafid;
m->tx.aname = xaname;
m->tx.uname = estrdup(m->tx.uname);
repack(&m->tx, &m->tpkt);
free(m->tx.uname);
m->tx.uname = "XXX";
}
break;
case Twalk:
if((m->fid = gethash(c->fid, m->tx.fid)) == nil){
@ -369,6 +419,10 @@ connthread(void *arg)
}
break;
case Tauth:
if(attached){
err(m, "authentication not required");
continue;
}
m->afid = fidnew(m->tx.afid);
if(puthash(c->fid, m->tx.afid, m->afid) < 0){
err(m, "duplicate fid");
@ -707,7 +761,8 @@ connoutthread(void *arg)
fidput(m->fid);
break;
case Twalk:
if(err && m->tx.fid != m->tx.newfid && m->newfid)
if(err || m->rx.nwqid < m->tx.nwname)
if(m->tx.fid != m->tx.newfid && m->newfid)
if(delhash(m->c->fid, m->newfid->cfid, m->newfid) == 0)
fidput(m->newfid);
break;
@ -851,6 +906,10 @@ fidnew(int cfid)
if(freefid == nil){
fidtab = erealloc(fidtab, (nfidtab+1)*sizeof(fidtab[0]));
if(nfidtab == xafid){
fidtab[nfidtab++] = nil;
fidtab = erealloc(fidtab, (nfidtab+1)*sizeof(fidtab[0]));
}
fidtab[nfidtab] = emalloc(sizeof(Fid));
freefid = fidtab[nfidtab];
freefid->fid = nfidtab++;
@ -1165,6 +1224,23 @@ restring(uchar *pkt, int pn, char *s)
PBIT16((uchar*)s-1, n);
}
void
repack(Fcall *f, uchar **ppkt)
{
uint n, nn;
uchar *pkt;
pkt = *ppkt;
n = GBIT32(pkt);
nn = sizeS2M(f);
if(nn > n){
free(pkt);
pkt = emalloc(nn);
*ppkt = pkt;
}
convS2M(f, pkt, nn);
}
void
rewritehdr(Fcall *f, uchar *pkt)
{

View file

@ -4,20 +4,46 @@
#include <fcall.h>
#include <thread.h>
int debug;
char *aname = "";
char *keypattern = "";
int fd;
int msize;
int doauth;
int afid = NOFID;
extern char *post9parg; /* clumsy hack */
void xauth(void);
AuthInfo* xauth_proxy(AuthGetkey *getkey, char *fmt, ...);
void
usage(void)
{
fprint(2, "usage: srv addr [srvname]\n");
fprint(2, "usage: srv [-a] [-A aname] [-k keypattern] addr [srvname]\n");
threadexitsall("usage");
}
void
threadmain(int argc, char **argv)
{
int fd;
char *addr, *service;
fmtinstall('F', fcallfmt);
fmtinstall('M', dirmodefmt);
ARGBEGIN{
case 'D':
debug = 1;
break;
case 'A':
/* BUG: should be able to repeat this and establish multiple afids */
aname = EARGF(usage());
break;
case 'a':
doauth = 1;
break;
case 'k':
keypattern = EARGF(usage());
break;
default:
usage();
}ARGEND
@ -28,14 +54,298 @@ threadmain(int argc, char **argv)
addr = netmkaddr(argv[0], "tcp", "9fs");
if((fd = dial(addr, nil, nil, nil)) < 0)
sysfatal("dial %s: %r", addr);
if(doauth)
xauth();
if(argc == 2)
service = argv[1];
else
service = argv[0];
if(post9pservice(fd, service) < 0)
sysfatal("post9pservice: %r");
threadexitsall(0);
}
void
do9p(Fcall *tx, Fcall *rx)
{
static uchar buf[9000];
static char ebuf[200];
int n;
n = convS2M(tx, buf, sizeof buf);
if(n == BIT16SZ){
werrstr("convS2M failed");
goto err;
}
if(debug)
fprint(2, "<- %F\n", tx);
if(write(fd, buf, n) != n)
goto err;
if((n = read9pmsg(fd, buf, sizeof buf)) < 0)
goto err;
if(n == 0){
werrstr("unexpected eof");
goto err;
}
if(convM2S(buf, n, rx) != n){
werrstr("convM2S failed");
goto err;
}
if(debug)
fprint(2, "-> %F\n", rx);
if(rx->type != Rerror && rx->type != tx->type+1){
werrstr("unexpected type");
goto err;
}
if(rx->tag != tx->tag){
werrstr("unexpected tag");
goto err;
}
return;
err:
rerrstr(ebuf, sizeof ebuf);
rx->ename = ebuf;
rx->type = Rerror;
return;
}
void
xauth(void)
{
Fcall tx, rx;
afid = 0;
tx.type = Tversion;
tx.tag = NOTAG;
tx.version = "9P2000";
tx.msize = 8192;
do9p(&tx, &rx);
if(rx.type == Rerror)
sysfatal("Tversion: %s", rx.ename);
msize = rx.msize;
tx.type = Tauth;
tx.tag = 1;
tx.afid = afid;
tx.uname = getuser();
tx.aname = aname;
do9p(&tx, &rx);
if(rx.type == Rerror){
fprint(2, "rx: %s\n", rx.ename);
afid = NOFID;
return;
}
if(xauth_proxy(auth_getkey, "proto=p9any role=client %s", keypattern) < 0)
sysfatal("authproxy: %r");
}
int
xread(void *buf, int n)
{
Fcall tx, rx;
tx.type = Tread;
tx.tag = 1;
tx.fid = 0; /* afid above */
tx.count = n;
tx.offset = 0;
do9p(&tx, &rx);
if(rx.type == Rerror){
werrstr("%s", rx.ename);
return -1;
}
if(rx.count > n){
werrstr("too much data returned");
return -1;
}
memmove(buf, rx.data, rx.count);
return rx.count;
}
int
xwrite(void *buf, int n)
{
Fcall tx, rx;
tx.type = Twrite;
tx.tag = 1;
tx.fid = 0; /* afid above */
tx.data = buf;
tx.count = n;
tx.offset = 0;
do9p(&tx, &rx);
if(rx.type == Rerror){
werrstr("%s", rx.ename);
return -1;
}
return n;
}
/*
* changed to add -A below
*/
#undef _exits
int
post9pservice(int fd, char *name)
{
int i;
char *ns, *s;
Waitmsg *w;
if((ns = getns()) == nil)
return -1;
s = smprint("unix!%s/%s", ns, name);
free(ns);
if(s == nil)
return -1;
switch(fork()){
case -1:
return -1;
case 0:
dup(fd, 0);
dup(fd, 1);
for(i=3; i<20; i++)
close(i);
if(doauth)
execlp("9pserve", "9pserve", "-u",
"-M",
smprint("%d", msize),
"-A",
aname,
smprint("%d", afid),
s, (char*)0);
else
execlp("9pserve", "9pserve", "-u", s, (char*)0);
fprint(2, "exec 9pserve: %r\n");
_exits("exec");
default:
w = wait();
if(w == nil)
return -1;
close(fd);
free(s);
if(w->msg && w->msg[0]){
free(w);
werrstr("9pserve failed");
return -1;
}
free(w);
return 0;
}
}
enum { ARgiveup = 100 };
static int
dorpc(AuthRpc *rpc, char *verb, char *val, int len, AuthGetkey *getkey)
{
int ret;
for(;;){
if((ret = auth_rpc(rpc, verb, val, len)) != ARneedkey && ret != ARbadkey)
return ret;
if(getkey == nil)
return ARgiveup; /* don't know how */
if((*getkey)(rpc->arg) < 0)
return ARgiveup; /* user punted */
}
}
/*
* this just proxies what the factotum tells it to.
*/
AuthInfo*
xfauth_proxy(AuthRpc *rpc, AuthGetkey *getkey, char *params)
{
char *buf;
int m, n, ret;
AuthInfo *a;
char oerr[ERRMAX];
rerrstr(oerr, sizeof oerr);
werrstr("UNKNOWN AUTH ERROR");
if(dorpc(rpc, "start", params, strlen(params), getkey) != ARok){
werrstr("fauth_proxy start: %r");
return nil;
}
buf = malloc(AuthRpcMax);
if(buf == nil)
return nil;
for(;;){
switch(dorpc(rpc, "read", nil, 0, getkey)){
case ARdone:
free(buf);
a = auth_getinfo(rpc);
errstr(oerr, sizeof oerr); /* no error, restore whatever was there */
return a;
case ARok:
if(xwrite(rpc->arg, rpc->narg) != rpc->narg){
werrstr("auth_proxy write fid: %r");
goto Error;
}
break;
case ARphase:
n = 0;
memset(buf, 0, AuthRpcMax);
while((ret = dorpc(rpc, "write", buf, n, getkey)) == ARtoosmall){
if(atoi(rpc->arg) > AuthRpcMax)
break;
m = xread(buf+n, atoi(rpc->arg)-n);
if(m <= 0){
if(m == 0)
werrstr("auth_proxy short read: %s", buf);
goto Error;
}
n += m;
}
if(ret != ARok){
werrstr("auth_proxy rpc write: %s: %r", buf);
goto Error;
}
break;
default:
werrstr("auth_proxy rpc: %r");
goto Error;
}
}
Error:
free(buf);
return nil;
}
AuthInfo*
xauth_proxy(AuthGetkey *getkey, char *fmt, ...)
{
char *p;
va_list arg;
AuthInfo *ai;
AuthRpc *rpc;
quotefmtinstall(); /* just in case */
va_start(arg, fmt);
p = vsmprint(fmt, arg);
va_end(arg);
rpc = auth_allocrpc();
if(rpc == nil){
free(p);
return nil;
}
ai = xfauth_proxy(rpc, getkey, p);
free(p);
auth_freerpc(rpc);
return ai;
}