tadd srv -a option - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 5c84c448b82c7bfdfeaae533783aa09317656e86
 (DIR) parent b8c9f31785f3243a52432023d4d555d490963769
 (HTM) Author: rsc <devnull@localhost>
       Date:   Mon, 21 Mar 2005 17:24:21 +0000
       
       add srv -a option
       
       Diffstat:
         M man/man4/9pserve.4                  |      38 ++++++++++++++++++++++++++++++-
         M man/man4/srv.4                      |      24 ++++++++++++++++++++++++
         M src/cmd/9pserve.c                   |     114 ++++++++++++++++++++++++++------
         M src/cmd/srv.c                       |     318 ++++++++++++++++++++++++++++++-
       
       4 files changed, 470 insertions(+), 24 deletions(-)
       ---
 (DIR) diff --git a/man/man4/9pserve.4 b/man/man4/9pserve.4
       t@@ -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
       t@@ -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)
 (DIR) diff --git a/man/man4/srv.4 b/man/man4/srv.4
       t@@ -3,6 +3,13 @@
        srv, 9fs \- start network file esrvice
        .SH SYNOPSIS
        .B srv
       +[
       +.B -a
       +]
       +[
       +.B -k
       +.I keypattern
       +]
        .I address
        [
        .I srvname
       t@@ -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
 (DIR) diff --git a/src/cmd/9pserve.c b/src/cmd/9pserve.c
       t@@ -69,6 +69,7 @@ struct Conn
                Queue *inq;
        };
        
       +char *xaname;
        char *addr;
        int afd;
        char adir[40];
       t@@ -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*);
       t@@ -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*);
       t@@ -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");
        }
       t@@ -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();
       t@@ -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);
        }
       t@@ -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)
        {
       t@@ -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){
       t@@ -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");
       t@@ -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;
       t@@ -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++;
       t@@ -1166,6 +1225,23 @@ restring(uchar *pkt, int pn, char *s)
        }
        
        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)
        {
                int i, n;
 (DIR) diff --git a/src/cmd/srv.c b/src/cmd/srv.c
       t@@ -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
       t@@ -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;
       +}
       +