tAdd sunrpc. - 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 551445b92c1f11d4f543e96790ff29762ab1ad10
 (DIR) parent fa256eecfaf035cd6c46335452357856dc0bd9e9
 (HTM) Author: rsc <devnull@localhost>
       Date:   Wed, 21 Apr 2004 03:04:30 +0000
       
       Add sunrpc.
       
       Diffstat:
         A src/libsunrpc/authunix.c            |      60 +++++++++++++++++++++++++++++++
         A src/libsunrpc/client.c              |     490 +++++++++++++++++++++++++++++++
         A src/libsunrpc/emalloc.c             |      34 +++++++++++++++++++++++++++++++
         A src/libsunrpc/error.c               |      37 +++++++++++++++++++++++++++++++
         A src/libsunrpc/fd.c                  |     107 +++++++++++++++++++++++++++++++
         A src/libsunrpc/fmt.c                 |      64 +++++++++++++++++++++++++++++++
         A src/libsunrpc/mkfile                |      31 +++++++++++++++++++++++++++++++
         A src/libsunrpc/mount3.c              |     727 ++++++++++++++++++++++++++++++
         A src/libsunrpc/net.c                 |      57 +++++++++++++++++++++++++++++++
         A src/libsunrpc/nfs3.c                |    4045 +++++++++++++++++++++++++++++++
         A src/libsunrpc/portmap.c             |     498 +++++++++++++++++++++++++++++++
         A src/libsunrpc/prog.c                |      74 +++++++++++++++++++++++++++++++
         A src/libsunrpc/rpc.c                 |     528 +++++++++++++++++++++++++++++++
         A src/libsunrpc/server.c              |     277 +++++++++++++++++++++++++++++++
         A src/libsunrpc/suncall.c             |      14 ++++++++++++++
         A src/libsunrpc/udp.c                 |     120 +++++++++++++++++++++++++++++++
       
       16 files changed, 7163 insertions(+), 0 deletions(-)
       ---
 (DIR) diff --git a/src/libsunrpc/authunix.c b/src/libsunrpc/authunix.c
       t@@ -0,0 +1,60 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <thread.h>
       +#include <sunrpc.h>
       +
       +uint
       +sunauthunixsize(SunAuthUnix *x)
       +{
       +        return 4 + sunstringsize(x->sysname) + 4 + 4 + 4 + 4*x->ng;
       +}
       +int
       +sunauthunixunpack(uchar *a, uchar *ea, uchar **pa, SunAuthUnix *x)
       +{
       +        int i;
       +
       +        if(sunuint32unpack(a, ea, &a, &x->stamp) < 0) goto Err;
       +        if(sunstringunpack(a, ea, &a, &x->sysname, 256) < 0) goto Err;
       +        if(sunuint32unpack(a, ea, &a, &x->uid) < 0) goto Err;
       +        if(sunuint32unpack(a, ea, &a, &x->gid) < 0) goto Err;
       +        if(sunuint32unpack(a, ea, &a, &x->ng) < 0 || x->ng > nelem(x->g)) goto Err;
       +        for(i=0; i<x->ng; i++)
       +                if(sunuint32unpack(a, ea, &a, &x->g[i]) < 0) goto Err;
       +
       +        *pa = a;
       +        return 0;
       +
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +sunauthunixpack(uchar *a, uchar *ea, uchar **pa, SunAuthUnix *x)
       +{
       +        int i;
       +
       +        if(sunuint32pack(a, ea, &a, &x->stamp) < 0) goto Err;
       +        if(sunstringpack(a, ea, &a, &x->sysname, 256) < 0) goto Err;
       +        if(sunuint32pack(a, ea, &a, &x->uid) < 0) goto Err;
       +        if(sunuint32pack(a, ea, &a, &x->gid) < 0) goto Err;
       +        if(sunuint32pack(a, ea, &a, &x->ng) < 0 || x->ng > nelem(x->g)) goto Err;
       +        for(i=0; i<x->ng; i++)
       +                if(sunuint32pack(a, ea, &a, &x->g[i]) < 0) goto Err;
       +
       +        *pa = a;
       +        return 0;
       +
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +sunauthunixprint(Fmt *fmt, SunAuthUnix *x)
       +{
       +        int i;
       +        fmtprint(fmt, "unix %.8lux %s %lud %lud (", (ulong)x->stamp,
       +                x->sysname, (ulong)x->uid, (ulong)x->gid);
       +        for(i=0; i<x->ng; i++)
       +                fmtprint(fmt, "%s%lud", i ? " ":"", (ulong)x->g[i]);
       +        fmtprint(fmt, ")");
       +}
 (DIR) diff --git a/src/libsunrpc/client.c b/src/libsunrpc/client.c
       t@@ -0,0 +1,490 @@
       +/*
       + * Sun RPC client.
       + */
       +#include <u.h>
       +#include <libc.h>
       +#include <thread.h>
       +#include <sunrpc.h>
       +
       +typedef struct Out Out;
       +struct Out
       +{
       +        char err[ERRMAX];        /* error string */
       +        Channel *creply;        /* send to finish rpc */
       +        uchar *p;                        /* pending request packet */
       +        int n;                                /* size of request */
       +        ulong tag;                        /* flush tag of pending request */
       +        ulong xid;                        /* xid of pending request */
       +        ulong st;                        /* first send time */
       +        ulong t;                        /* resend time */
       +        int nresend;                /* number of resends */
       +        SunRpc rpc;                /* response rpc */
       +};
       +
       +static void
       +udpThread(void *v)
       +{
       +        uchar *p, *buf;
       +        Ioproc *io;
       +        int n;
       +        SunClient *cli;
       +        enum { BufSize = 65536 };
       +
       +        cli = v;
       +        buf = emalloc(BufSize);
       +        io = ioproc();
       +        p = nil;
       +        for(;;){
       +                n = ioread(io, cli->fd, buf, BufSize);
       +                if(n <= 0)
       +                        break;
       +                p = emalloc(4+n);
       +                memmove(p+4, buf, n);
       +                p[0] = n>>24;
       +                p[1] = n>>16;
       +                p[2] = n>>8;
       +                p[3] = n;
       +                if(sendp(cli->readchan, p) == 0)
       +                        break;
       +                p = nil;
       +        }
       +        free(p);
       +        closeioproc(io);
       +        while(send(cli->dying, nil) == -1)
       +                ;
       +}
       +
       +static void
       +netThread(void *v)
       +{
       +        uchar *p, buf[4];
       +        Ioproc *io;
       +        uint n, tot;
       +        int done;
       +        SunClient *cli;
       +
       +        cli = v;
       +        io = ioproc();
       +        tot = 0;
       +        p = nil;
       +        for(;;){
       +                n = ioreadn(io, cli->fd, buf, 4);
       +                if(n != 4)
       +                        break;
       +                n = (buf[0]<<24)|(buf[1]<<16)|(buf[2]<<8)|buf[3];
       +                if(cli->chatty)
       +                        fprint(2, "%.8ux...", n);
       +                done = n&0x80000000;
       +                n &= ~0x80000000;
       +                if(tot == 0){
       +                        p = emalloc(4+n);
       +                        tot = 4;
       +                }else
       +                        p = erealloc(p, tot+n);
       +                if(ioreadn(io, cli->fd, p+tot, n) != n)
       +                        break;
       +                tot += n;
       +                if(done){
       +                        p[0] = tot>>24;
       +                        p[1] = tot>>16;
       +                        p[2] = tot>>8;
       +                        p[3] = tot;
       +                        if(sendp(cli->readchan, p) == 0)
       +                                break;
       +                        p = nil;
       +                        tot = 0;
       +                }
       +        }
       +        free(p);
       +        closeioproc(io);
       +        while(send(cli->dying, 0) == -1)
       +                ;
       +}
       +
       +static void
       +timerThread(void *v)
       +{
       +        Ioproc *io;
       +        SunClient *cli;
       +
       +        cli = v;
       +        io = ioproc();
       +        for(;;){
       +                if(iosleep(io, 200) < 0)
       +                        break;
       +                if(sendul(cli->timerchan, 0) == 0)
       +                        break;
       +        }
       +        closeioproc(io);
       +        while(send(cli->dying, 0) == -1)
       +                ;
       +}
       +
       +static ulong
       +msec(void)
       +{
       +        return nsec()/1000000;
       +}
       +
       +static ulong
       +twait(ulong rtt, int nresend)
       +{
       +        ulong t;
       +
       +        t = rtt;
       +        if(nresend <= 1)
       +                {}
       +        else if(nresend <= 3)
       +                t *= 2;
       +        else if(nresend <= 18)
       +                t <<= nresend-2;
       +        else
       +                t = 60*1000;
       +        if(t > 60*1000)
       +                t = 60*1000;
       +
       +        return t;
       +}
       +
       +static void
       +rpcMuxThread(void *v)
       +{
       +        uchar *buf, *p, *ep;
       +        int i, n, nout, mout;
       +        ulong t, xidgen, tag;
       +        Alt a[5];
       +        Out *o, **out;
       +        SunRpc rpc;
       +        SunClient *cli;
       +
       +        cli = v;
       +        mout = 16;
       +        nout = 0;
       +        out = emalloc(mout*sizeof(out[0]));
       +        xidgen = truerand();
       +
       +        a[0].op = CHANRCV;
       +        a[0].c = cli->rpcchan;
       +        a[0].v = &o;
       +        a[1].op = CHANNOP;
       +        a[1].c = cli->timerchan;
       +        a[1].v = nil;
       +        a[2].op = CHANRCV;
       +        a[2].c = cli->flushchan;
       +        a[2].v = &tag;
       +        a[3].op = CHANRCV;
       +        a[3].c = cli->readchan;
       +        a[3].v = &buf;
       +        a[4].op = CHANEND;
       +
       +        for(;;){
       +                switch(alt(a)){
       +                case 0:        /* o = <-rpcchan */
       +                        if(o == nil)
       +                                goto Done;
       +                        cli->nsend++;
       +                        /* set xid */
       +                        o->xid = ++xidgen;
       +                        if(cli->needcount)
       +                                p = o->p+4;
       +                        else
       +                                p = o->p;
       +                        p[0] = xidgen>>24;
       +                        p[1] = xidgen>>16;
       +                        p[2] = xidgen>>8;
       +                        p[3] = xidgen;
       +                        if(write(cli->fd, o->p, o->n) != o->n){
       +                                free(o->p);
       +                                o->p = nil;
       +                                snprint(o->err, sizeof o->err, "write: %r");
       +                                sendp(o->creply, 0);
       +                                break;
       +                        }
       +                        if(nout >= mout){
       +                                mout *= 2;
       +                                out = erealloc(out, mout*sizeof(out[0]));
       +                        }
       +                        o->st = msec();
       +                        o->nresend = 0;
       +                        o->t = o->st + twait(cli->rtt.avg, 0);
       +if(cli->chatty) fprint(2, "send %lux %lud %lud\n", o->xid, o->st, o->t);
       +                        out[nout++] = o;
       +                        a[1].op = CHANRCV;
       +                        break;
       +
       +                case 1:        /* <-timerchan */
       +                        t = msec();
       +                        for(i=0; i<nout; i++){
       +                                o = out[i];
       +                                if((int)(t - o->t) > 0){
       +if(cli->chatty) fprint(2, "resend %lux %lud %lud\n", o->xid, t, o->t);
       +                                        if(cli->maxwait && t - o->st >= cli->maxwait){
       +                                                free(o->p);
       +                                                o->p = nil;
       +                                                strcpy(o->err, "timeout");
       +                                                sendp(o->creply, 0);
       +                                                out[i--] = out[--nout];
       +                                                continue;
       +                                        }
       +                                        cli->nresend++;
       +                                        o->nresend++;
       +                                        o->t = t + twait(cli->rtt.avg, o->nresend);
       +                                        if(write(cli->fd, o->p, o->n) != o->n){
       +                                                free(o->p);
       +                                                o->p = nil;
       +                                                snprint(o->err, sizeof o->err, "rewrite: %r");
       +                                                sendp(o->creply, 0);
       +                                                out[i--] = out[--nout];
       +                                                continue;
       +                                        }
       +                                }
       +                        }
       +                        /* stop ticking if no work; rpcchan will turn it back on */
       +                        if(nout == 0)
       +                                a[1].op = CHANNOP;
       +                        break;
       +                        
       +                case 2:        /* tag = <-flushchan */
       +                        for(i=0; i<nout; i++){
       +                                o = out[i];
       +                                if(o->tag == tag){
       +                                        out[i--] = out[--nout];
       +                                        strcpy(o->err, "flushed");
       +                                        free(o->p);
       +                                        o->p = nil;
       +                                        sendp(o->creply, 0);
       +                                }
       +                        }
       +                        break;
       +
       +                case 3:        /* buf = <-readchan */
       +                        p = buf;
       +                        n = (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
       +                        p += 4;
       +                        ep = p+n;
       +                        if(sunrpcunpack(p, ep, &p, &rpc) < 0){
       +                                fprint(2, "%s: in: %.*H unpack failed\n", argv0, n, buf+4);
       +                                free(buf);
       +                                break;
       +                        }
       +                        if(cli->chatty)
       +                                fprint(2, "in: %B\n", &rpc);
       +                        if(rpc.iscall){
       +                                fprint(2, "did not get reply\n");
       +                                free(buf);
       +                                break;
       +                        }
       +                        o = nil;
       +                        for(i=0; i<nout; i++){
       +                                o = out[i];
       +                                if(o->xid == rpc.xid)
       +                                        break;
       +                        }
       +                        if(i==nout){
       +                                if(cli->chatty) fprint(2, "did not find waiting request\n");
       +                                free(buf);
       +                                break;
       +                        }
       +                        out[i] = out[--nout];
       +                        free(o->p);
       +                        o->p = nil;
       +                        if(rpc.status == SunSuccess){
       +                                o->p = buf;
       +                                o->rpc = rpc;
       +                        }else{
       +                                o->p = nil;
       +                                free(buf);
       +                                sunerrstr(rpc.status);
       +                                rerrstr(o->err, sizeof o->err);
       +                        }
       +                        sendp(o->creply, 0);
       +                        break;
       +                }
       +        }
       +Done:
       +        free(out);
       +        sendp(cli->dying, 0);
       +}
       +
       +SunClient*
       +sundial(char *address)
       +{
       +        int fd;
       +        SunClient *cli;
       +
       +        if((fd = dial(address, 0, 0, 0)) < 0)
       +                return nil;
       +
       +        cli = emalloc(sizeof(SunClient));
       +        cli->fd = fd;
       +        cli->maxwait = 15000;
       +        cli->rtt.avg = 1000;
       +        cli->dying = chancreate(sizeof(void*), 0);
       +        cli->rpcchan = chancreate(sizeof(Out*), 0);
       +        cli->timerchan = chancreate(sizeof(ulong), 0);
       +        cli->flushchan = chancreate(sizeof(ulong), 0);
       +        cli->readchan = chancreate(sizeof(uchar*), 0);
       +        if(strstr(address, "udp!")){
       +                cli->needcount = 0;
       +                cli->nettid = threadcreate(udpThread, cli, SunStackSize);
       +                cli->timertid = threadcreate(timerThread, cli, SunStackSize);
       +        }else{
       +                cli->needcount = 1;
       +                cli->nettid = threadcreate(netThread, cli, SunStackSize);
       +                /* assume reliable: don't need timer */
       +                /* BUG: netThread should know how to redial */
       +        }
       +        threadcreate(rpcMuxThread, cli, SunStackSize);
       +
       +        return cli;
       +}
       +
       +void
       +sunclientclose(SunClient *cli)
       +{
       +        int n;
       +
       +        /*
       +         * Threadints get you out of any stuck system calls
       +         * or thread rendezvouses, but do nothing if the thread
       +         * is in the ready state.  Keep interrupting until it takes.
       +         */
       +        n = 0;
       +        if(!cli->timertid)
       +                n++;
       +        while(n < 2){
       +                threadint(cli->nettid);
       +                if(cli->timertid)
       +                        threadint(cli->timertid);
       +                yield();
       +                while(nbrecv(cli->dying, nil) == 1)
       +                        n++;
       +        }
       +
       +        sendp(cli->rpcchan, 0);
       +        recvp(cli->dying);
       +
       +        /* everyone's gone: clean up */
       +        close(cli->fd);
       +        chanfree(cli->flushchan);
       +        chanfree(cli->readchan);
       +        chanfree(cli->timerchan);
       +        free(cli);
       +}
       +        
       +void
       +sunclientflushrpc(SunClient *cli, ulong tag)
       +{
       +        sendul(cli->flushchan, tag);
       +}
       +
       +void
       +sunclientprog(SunClient *cli, SunProg *p)
       +{
       +        if(cli->nprog%16 == 0)
       +                cli->prog = erealloc(cli->prog, (cli->nprog+16)*sizeof(cli->prog[0]));
       +        cli->prog[cli->nprog++] = p;
       +}
       +
       +int
       +sunclientrpc(SunClient *cli, ulong tag, SunCall *tx, SunCall *rx, uchar **tofree)
       +{
       +        uchar *bp, *p, *ep;
       +        int i, n1, n2, n, nn;
       +        Out o;
       +        SunProg *prog;
       +        SunStatus ok;
       +
       +        for(i=0; i<cli->nprog; i++)
       +                if(cli->prog[i]->prog == tx->rpc.prog && cli->prog[i]->vers == tx->rpc.vers)
       +                        break;
       +        if(i==cli->nprog){
       +                werrstr("unknown sun rpc program %d version %d", tx->rpc.prog, tx->rpc.vers);
       +                return -1;
       +        }
       +        prog = cli->prog[i];
       +
       +        if(cli->chatty){
       +                fprint(2, "out: %B\n", &tx->rpc);
       +                fprint(2, "\t%C\n", tx);
       +        }
       +
       +        n1 = sunrpcsize(&tx->rpc);
       +        n2 = suncallsize(prog, tx);
       +
       +        n = n1+n2;
       +        if(cli->needcount)
       +                n += 4;
       +
       +        /*
       +         * The dance with 100 is to leave some padding in case
       +         * suncallsize is slightly underestimating.  If this happens,
       +         * the pack will succeed and then we can give a good size
       +         * mismatch error below.  Otherwise the pack fails with
       +         * garbage args, which is less helpful.
       +         */
       +        bp = emalloc(n+100);
       +        ep = bp+n+100;
       +        p = bp;
       +        if(cli->needcount){
       +                nn = n-4;
       +                p[0] = (nn>>24)|0x80;
       +                p[1] = nn>>16;
       +                p[2] = nn>>8;
       +                p[3] = nn;
       +                p += 4;
       +        }
       +        if((ok = sunrpcpack(p, ep, &p, &tx->rpc)) != SunSuccess
       +        || (ok = suncallpack(prog, p, ep, &p, tx)) != SunSuccess){
       +                sunerrstr(ok);
       +                free(bp);
       +                return -1;
       +        }
       +        ep -= 100;
       +        if(p != ep){
       +                werrstr("rpc: packet size mismatch %d %ld %ld", n, ep-bp, p-bp);
       +                free(bp);
       +                return -1;
       +        }
       +
       +        memset(&o, 0, sizeof o);
       +        o.creply = chancreate(sizeof(void*), 0);
       +        o.tag = tag;
       +        o.p = bp;
       +        o.n = n;
       +
       +        sendp(cli->rpcchan, &o);
       +        recvp(o.creply);
       +        chanfree(o.creply);
       +
       +        if(o.p == nil){
       +                werrstr("%s", o.err);
       +                return -1;
       +        }
       +
       +        p = o.rpc.data;
       +        ep = p+o.rpc.ndata;
       +        rx->rpc = o.rpc;
       +        rx->rpc.proc = tx->rpc.proc;
       +        rx->rpc.prog = tx->rpc.prog;
       +        rx->rpc.vers = tx->rpc.vers;
       +        rx->type = (rx->rpc.proc<<1)|1;
       +        if((ok = suncallunpack(prog, p, ep, &p, rx)) != SunSuccess){
       +                sunerrstr(ok);
       +                werrstr("unpack: %r");
       +                free(o.p);
       +                return -1;
       +        }
       +
       +        if(cli->chatty){
       +                fprint(2, "in: %B\n", &rx->rpc);
       +                fprint(2, "in:\t%C\n", rx);
       +        }
       +
       +        if(tofree)
       +                *tofree = o.p;
       +        else
       +                free(o.p);
       +
       +        return 0;
       +}
 (DIR) diff --git a/src/libsunrpc/emalloc.c b/src/libsunrpc/emalloc.c
       t@@ -0,0 +1,34 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <thread.h>
       +#include <sunrpc.h>
       +
       +void*
       +emalloc(ulong n)
       +{
       +        void *v;
       +
       +        v = mallocz(n, 1);
       +        if(v == nil)
       +{
       +abort();
       +                sysfatal("out of memory");
       +}
       +        setmalloctag(v, getcallerpc(&n));
       +        return v;
       +}
       +
       +void*
       +erealloc(void *v, ulong n)
       +{
       +        v = realloc(v, n);
       +        if(v == nil)
       +{
       +abort();
       +                sysfatal("out of memory");
       +}
       +        setrealloctag(v, getcallerpc(&n));
       +        return v;
       +}
       +
       +
 (DIR) diff --git a/src/libsunrpc/error.c b/src/libsunrpc/error.c
       t@@ -0,0 +1,37 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <thread.h>
       +#include <sunrpc.h>
       +
       +static struct {
       +        SunStatus status;
       +        char *msg;
       +} tab[] = {
       +        SunProgUnavail,        "program unavailable",
       +        SunProgMismatch,        "program mismatch",
       +        SunProcUnavail,        "procedure unavailable",
       +        SunGarbageArgs,        "garbage args",
       +        SunSystemErr,                "system error",
       +        SunRpcMismatch,        "rpc mismatch",
       +        SunAuthBadCred,        "bad auth cred",
       +        SunAuthRejectedCred,        "rejected auth cred",
       +        SunAuthBadVerf,        "bad auth verf",
       +        SunAuthRejectedVerf,        "rejected auth verf",
       +        SunAuthTooWeak,        "auth too weak",
       +        SunAuthInvalidResp,        "invalid auth response",
       +        SunAuthFailed,                "auth failed",
       +};
       +
       +void
       +sunerrstr(SunStatus status)
       +{
       +        int i;
       +
       +        for(i=0; i<nelem(tab); i++){
       +                if(tab[i].status == status){
       +                        werrstr(tab[i].msg);
       +                        return;
       +                }
       +        }
       +        werrstr("unknown sun error %d", (int)status);
       +}
 (DIR) diff --git a/src/libsunrpc/fd.c b/src/libsunrpc/fd.c
       t@@ -0,0 +1,107 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <thread.h>
       +#include <sunrpc.h>
       +
       +enum
       +{
       +        MaxRead = 17000,
       +};
       +
       +typedef struct SunMsgFd SunMsgFd;
       +struct SunMsgFd
       +{
       +        SunMsg msg;
       +        int fd;
       +};
       +
       +typedef struct Arg Arg;
       +struct Arg
       +{
       +        SunSrv *srv;
       +        Channel *creply;
       +        Channel *csync;
       +        int fd;
       +};
       +
       +static void
       +sunfdread(void *v)
       +{
       +        uint n, tot;
       +        int done;
       +        uchar buf[4], *p;
       +        Arg arg = *(Arg*)v;
       +        SunMsgFd *msg;
       +
       +        sendp(arg.csync, 0);
       +
       +        p = nil;
       +        tot = 0;
       +        for(;;){
       +                n = readn(arg.fd, buf, 4);
       +                if(n != 4)
       +                        break;
       +                n = (buf[0]<<24)|(buf[1]<<16)|(buf[2]<<8)|buf[3];
       +if(arg.srv->chatty) fprint(2, "%.8ux...", n);
       +                done = n&0x80000000;
       +                n &= ~0x80000000;
       +                p = erealloc(p, tot+n);
       +                if(readn(arg.fd, p+tot, n) != n)
       +                        break;
       +                tot += n;
       +                if(done){
       +                        msg = emalloc(sizeof(SunMsgFd));
       +                        msg->msg.data = p;
       +                        msg->msg.count = tot;
       +                        msg->msg.creply = arg.creply;
       +                        sendp(arg.srv->crequest, msg);
       +                        p = nil;
       +                        tot = 0;
       +                }
       +        }
       +}
       +
       +static void
       +sunfdwrite(void *v)
       +{
       +        uchar buf[4];
       +        u32int n;
       +        Arg arg = *(Arg*)v;
       +        SunMsgFd *msg;
       +
       +        sendp(arg.csync, 0);
       +
       +        while((msg = recvp(arg.creply)) != nil){
       +                n = msg->msg.count;
       +                buf[0] = (n>>24)|0x80;
       +                buf[1] = n>>16;
       +                buf[2] = n>>8;
       +                buf[3] = n;
       +                if(write(arg.fd, buf, 4) != 4
       +                || write(arg.fd, msg->msg.data, msg->msg.count) != msg->msg.count)
       +                        fprint(2, "sunfdwrite: %r\n");
       +                free(msg->msg.data);
       +                free(msg);
       +        }
       +}
       +
       +int
       +sunsrvfd(SunSrv *srv, int fd)
       +{
       +        Arg *arg;
       +
       +        arg = emalloc(sizeof(Arg));
       +        arg->fd = fd;
       +        arg->srv = srv;
       +        arg->csync = chancreate(sizeof(void*), 0);
       +        arg->creply = chancreate(sizeof(SunMsg*), 10);
       +
       +        proccreate(sunfdread, arg, SunStackSize);
       +        proccreate(sunfdwrite, arg, SunStackSize);
       +        recvp(arg->csync);
       +        recvp(arg->csync);
       +
       +        chanfree(arg->csync);
       +        free(arg);
       +        return 0;
       +}
 (DIR) diff --git a/src/libsunrpc/fmt.c b/src/libsunrpc/fmt.c
       t@@ -0,0 +1,64 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <thread.h>
       +#include <sunrpc.h>
       +
       +/*
       + * print formatters
       + */
       +int
       +sunrpcfmt(Fmt *f)
       +{
       +        SunRpc *rpc;
       +
       +        rpc = va_arg(f->args, SunRpc*);
       +        sunrpcprint(f, rpc);
       +        return 0;
       +}
       +
       +static SunProg **fmtProg;
       +static int nfmtProg;
       +static RWLock fmtLock;
       +
       +void
       +sunfmtinstall(SunProg *p)
       +{
       +        int i;
       +
       +        wlock(&fmtLock);
       +        for(i=0; i<nfmtProg; i++){
       +                if(fmtProg[i] == p){
       +                        wunlock(&fmtLock);
       +                        return;
       +                }
       +        }
       +        if(nfmtProg%16 == 0)
       +                fmtProg = erealloc(fmtProg, sizeof(fmtProg[0])*(nfmtProg+16));
       +        fmtProg[nfmtProg++] = p;
       +        wunlock(&fmtLock);
       +}
       +
       +int
       +suncallfmt(Fmt *f)
       +{
       +        int i;
       +        void (*fmt)(Fmt*, SunCall*);
       +        SunCall *c;
       +        SunProg *p;
       +
       +        c = va_arg(f->args, SunCall*);
       +        rlock(&fmtLock);
       +        for(i=0; i<nfmtProg; i++){
       +                p = fmtProg[i];
       +                if(p->prog == c->rpc.prog && p->vers == c->rpc.vers){
       +                        runlock(&fmtLock);
       +                        if(c->type < 0 || c->type >= p->nproc || (fmt=p->proc[c->type].fmt) == nil)
       +                                return fmtprint(f, "unknown proc %c%d", "TR"[c->type&1], c->type>>1);
       +                        (*fmt)(f, c);
       +                        return 0;
       +                }
       +        }
       +        runlock(&fmtLock);
       +        fmtprint(f, "<sunrpc %d %d %c%d>", c->rpc.prog, c->rpc.vers, "TR"[c->type&1], c->type>>1);
       +        return 0;
       +}
 (DIR) diff --git a/src/libsunrpc/mkfile b/src/libsunrpc/mkfile
       t@@ -0,0 +1,31 @@
       +PLAN9=../..
       +<$PLAN9/src/mkhdr
       +
       +PROTO=\
       +        mount3.$O\
       +        nfs3.$O\
       +        portmap.$O\
       +
       +OFILES=\
       +        authunix.$O\
       +        client.$O\
       +        emalloc.$O\
       +        error.$O\
       +        fd.$O\
       +        fmt.$O\
       +        net.$O\
       +        prog.$O\
       +        rpc.$O\
       +        server.$O\
       +        suncall.$O\
       +        udp.$O\
       +        $PROTO\
       +
       +HFILES=\
       +        $PLAN9/include/sunrpc.h\
       +
       +LIB=libsunrpc.a
       +
       +<$PLAN9/src/mksyslib
       +
       +mount3.$O: $PLAN9/include/nfs3.h
 (DIR) diff --git a/src/libsunrpc/mount3.c b/src/libsunrpc/mount3.c
       t@@ -0,0 +1,727 @@
       +/*
       + * SUN NFSv3 Mounter.  See RFC 1813
       + */
       +
       +#include <u.h>
       +#include <libc.h>
       +#include <thread.h>
       +#include <sunrpc.h>
       +#include <nfs3.h>
       +
       +void
       +nfsmount3tnullprint(Fmt *fmt, NfsMount3TNull *x)
       +{
       +        USED(x);
       +        fmtprint(fmt, "%s\n", "NfsMount3TNull");
       +}
       +uint
       +nfsmount3tnullsize(NfsMount3TNull *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0;
       +        return a;
       +}
       +int
       +nfsmount3tnullpack(uchar *a, uchar *ea, uchar **pa, NfsMount3TNull *x)
       +{
       +        USED(ea);
       +        USED(x);
       +        *pa = a;
       +        return 0;
       +}
       +int
       +nfsmount3tnullunpack(uchar *a, uchar *ea, uchar **pa, NfsMount3TNull *x)
       +{
       +        USED(ea);
       +        USED(x);
       +        *pa = a;
       +        return 0;
       +}
       +void
       +nfsmount3rnullprint(Fmt *fmt, NfsMount3RNull *x)
       +{
       +        USED(x);
       +        fmtprint(fmt, "%s\n", "NfsMount3RNull");
       +}
       +uint
       +nfsmount3rnullsize(NfsMount3RNull *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0;
       +        return a;
       +}
       +int
       +nfsmount3rnullpack(uchar *a, uchar *ea, uchar **pa, NfsMount3RNull *x)
       +{
       +        USED(ea);
       +        USED(x);
       +        *pa = a;
       +        return 0;
       +}
       +int
       +nfsmount3rnullunpack(uchar *a, uchar *ea, uchar **pa, NfsMount3RNull *x)
       +{
       +        USED(ea);
       +        USED(x);
       +        *pa = a;
       +        return 0;
       +}
       +void
       +nfsmount3tmntprint(Fmt *fmt, NfsMount3TMnt *x)
       +{
       +        fmtprint(fmt, "%s\n", "NfsMount3TMnt");
       +        fmtprint(fmt, "\t%s=", "path");
       +        fmtprint(fmt, "\"%s\"", x->path);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfsmount3tmntsize(NfsMount3TMnt *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + sunstringsize(x->path);
       +        return a;
       +}
       +int
       +nfsmount3tmntpack(uchar *a, uchar *ea, uchar **pa, NfsMount3TMnt *x)
       +{
       +        if(sunstringpack(a, ea, &a, &x->path, 1024) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfsmount3tmntunpack(uchar *a, uchar *ea, uchar **pa, NfsMount3TMnt *x)
       +{
       +        if(sunstringunpack(a, ea, &a, &x->path, 1024) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfsmount3rmntprint(Fmt *fmt, NfsMount3RMnt *x)
       +{
       +        fmtprint(fmt, "%s\n", "NfsMount3RMnt");
       +        fmtprint(fmt, "\t%s=", "status");
       +        fmtprint(fmt, "%ud", x->status);
       +        fmtprint(fmt, "\n");
       +        switch(x->status){
       +        case 0:
       +                fmtprint(fmt, "\t%s=", "handle");
       +                fmtprint(fmt, "%.*H", x->len, x->handle);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +}
       +uint
       +nfsmount3rmntsize(NfsMount3RMnt *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4;
       +        switch(x->status){
       +        case 0:
       +                a = a + sunvaropaquesize(x->len);
       +                a = a + 4 + 4 * x->nauth;
       +                break;
       +        }
       +        a = a;
       +        return a;
       +}
       +uint
       +nfsmount1rmntsize(NfsMount3RMnt *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4;
       +        switch(x->status){
       +        case 0:
       +                a = a + NfsMount1HandleSize;
       +                break;
       +        }
       +        return a;
       +}
       +
       +int
       +nfsmount3rmntpack(uchar *a, uchar *ea, uchar **pa, NfsMount3RMnt *x)
       +{
       +        int i;
       +        if(sunuint32pack(a, ea, &a, &x->status) < 0) goto Err;
       +        switch(x->status){
       +        case 0:
       +                if(sunvaropaquepack(a, ea, &a, &x->handle, &x->len, NfsMount3MaxHandleSize) < 0) goto Err;
       +                if(sunuint32pack(a, ea, &a, &x->nauth) < 0) goto Err;
       +                for(i=0; i<x->nauth; i++)
       +                        if(sunuint32pack(a, ea, &a, &x->auth[i]) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfsmount1rmntpack(uchar *a, uchar *ea, uchar **pa, NfsMount3RMnt *x)
       +{
       +        if(sunuint32pack(a, ea, &a, &x->status) < 0) goto Err;
       +        switch(x->status){
       +        case 0:
       +                if(x->len != NfsMount1HandleSize)
       +                        goto Err;
       +                if(sunfixedopaquepack(a, ea, &a, x->handle, NfsMount1HandleSize) < 0) goto Err;
       +                if(x->nauth != 0)
       +                        goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfsmount1rmntunpack(uchar *a, uchar *ea, uchar **pa, NfsMount3RMnt *x)
       +{
       +        if(sunuint32unpack(a, ea, &a, &x->status) < 0) goto Err;
       +        switch(x->status){
       +        case 0:
       +                x->len = NfsMount1HandleSize;
       +                x->nauth = 0;
       +                x->auth = 0;
       +                if(sunfixedopaqueunpack(a, ea, &a, x->handle, NfsMount1HandleSize) < 0) goto Err;
       +                if(x->nauth != 0)
       +                        goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +
       +int
       +nfsmount3rmntunpack(uchar *a, uchar *ea, uchar **pa, NfsMount3RMnt *x)
       +{
       +        int i;
       +
       +        if(sunuint32unpack(a, ea, &a, &x->status) < 0) goto Err;
       +        switch(x->status){
       +        case 0:
       +                if(sunvaropaqueunpack(a, ea, &a, &x->handle, &x->len, NfsMount3MaxHandleSize) < 0) goto Err;
       +                if(sunuint32unpack(a, ea, &a, &x->nauth) < 0) goto Err;
       +                x->auth = (u32int*)a;
       +                for(i=0; i<x->nauth; i++)
       +                        if(sunuint32unpack(a, ea, &a, &x->auth[i]) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfsmount3tdumpprint(Fmt *fmt, NfsMount3TDump *x)
       +{
       +        USED(x);
       +        fmtprint(fmt, "%s\n", "NfsMount3TDump");
       +}
       +uint
       +nfsmount3tdumpsize(NfsMount3TDump *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0;
       +        return a;
       +}
       +int
       +nfsmount3tdumppack(uchar *a, uchar *ea, uchar **pa, NfsMount3TDump *x)
       +{
       +        USED(ea);
       +        USED(x);
       +        *pa = a;
       +        return 0;
       +}
       +int
       +nfsmount3tdumpunpack(uchar *a, uchar *ea, uchar **pa, NfsMount3TDump *x)
       +{
       +        USED(ea);
       +        USED(x);
       +        *pa = a;
       +        return 0;
       +}
       +void
       +nfsmount3entryprint(Fmt *fmt, NfsMount3Entry *x)
       +{
       +        fmtprint(fmt, "%s\n", "NfsMount3Entry");
       +        fmtprint(fmt, "\t%s=", "host");
       +        fmtprint(fmt, "\"%s\"", x->host);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "path");
       +        fmtprint(fmt, "\"%s\"", x->path);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfsmount3entrysize(NfsMount3Entry *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + sunstringsize(x->host) + sunstringsize(x->path);
       +        return a;
       +}
       +int
       +nfsmount3entrypack(uchar *a, uchar *ea, uchar **pa, NfsMount3Entry *x)
       +{
       +        u1int one;
       +
       +        one = 1;
       +        if(sunuint1pack(a, ea, &a, &one) < 0) goto Err;
       +        if(sunstringpack(a, ea, &a, &x->host, 255) < 0) goto Err;
       +        if(sunstringpack(a, ea, &a, &x->path, 1024) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfsmount3entryunpack(uchar *a, uchar *ea, uchar **pa, NfsMount3Entry *x)
       +{
       +        u1int one;
       +
       +        if(sunuint1unpack(a, ea, &a, &one) < 0 || one != 1) goto Err;
       +        if(sunstringunpack(a, ea, &a, &x->host, NfsMount3MaxNameSize) < 0) goto Err;
       +        if(sunstringunpack(a, ea, &a, &x->path, NfsMount3MaxPathSize) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfsmount3rdumpprint(Fmt *fmt, NfsMount3RDump *x)
       +{
       +        USED(x);
       +        fmtprint(fmt, "%s\n", "NfsMount3RDump");
       +}
       +uint
       +nfsmount3rdumpsize(NfsMount3RDump *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0;
       +        a += x->count;
       +        a += 4;
       +        return a;
       +}
       +int
       +nfsmount3rdumppack(uchar *a, uchar *ea, uchar **pa, NfsMount3RDump *x)
       +{
       +        u1int zero;
       +
       +        zero = 0;
       +        if(a+x->count > ea) goto Err;
       +        memmove(a, x->data, x->count);
       +        a += x->count;
       +        if(sunuint1pack(a, ea, &a, &zero) < 0)
       +                goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfsmount3rdumpunpack(uchar *a, uchar *ea, uchar **pa, NfsMount3RDump *x)
       +{
       +        int i;
       +        uchar *oa;
       +        u1int u1;
       +        u32int u32;
       +
       +        oa = a;
       +        for(i=0;; i++){
       +                if(sunuint1unpack(a, ea, &a, &u1) < 0)
       +                        goto Err;
       +                if(u1 == 0)
       +                        break;
       +                if(sunuint32unpack(a, ea, &a, &u32) < 0
       +                || u32 > NfsMount3MaxNameSize
       +                || (a+=u32) >= ea
       +                || sunuint32unpack(a, ea, &a, &u32) < 0
       +                || u32 > NfsMount3MaxPathSize
       +                || (a+=u32) >= ea)
       +                        goto Err;
       +        }
       +        x->count = (a-4) - oa;
       +        x->data = oa;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfsmount3tumntprint(Fmt *fmt, NfsMount3TUmnt *x)
       +{
       +        fmtprint(fmt, "%s\n", "NfsMount3TUmnt");
       +        fmtprint(fmt, "\t%s=", "path");
       +        fmtprint(fmt, "\"%s\"", x->path);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfsmount3tumntsize(NfsMount3TUmnt *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + sunstringsize(x->path);
       +        return a;
       +}
       +int
       +nfsmount3tumntpack(uchar *a, uchar *ea, uchar **pa, NfsMount3TUmnt *x)
       +{
       +        if(sunstringpack(a, ea, &a, &x->path, 1024) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfsmount3tumntunpack(uchar *a, uchar *ea, uchar **pa, NfsMount3TUmnt *x)
       +{
       +        if(sunstringunpack(a, ea, &a, &x->path, 1024) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfsmount3rumntprint(Fmt *fmt, NfsMount3RUmnt *x)
       +{
       +        USED(x);
       +        fmtprint(fmt, "%s\n", "NfsMount3RUmnt");
       +}
       +uint
       +nfsmount3rumntsize(NfsMount3RUmnt *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0;
       +        return a;
       +}
       +int
       +nfsmount3rumntpack(uchar *a, uchar *ea, uchar **pa, NfsMount3RUmnt *x)
       +{
       +        USED(ea);
       +        USED(x);
       +        *pa = a;
       +        return 0;
       +}
       +int
       +nfsmount3rumntunpack(uchar *a, uchar *ea, uchar **pa, NfsMount3RUmnt *x)
       +{
       +        USED(ea);
       +        USED(x);
       +        *pa = a;
       +        return 0;
       +}
       +void
       +nfsmount3tumntallprint(Fmt *fmt, NfsMount3TUmntall *x)
       +{
       +        USED(x);
       +        fmtprint(fmt, "%s\n", "NfsMount3TUmntall");
       +}
       +uint
       +nfsmount3tumntallsize(NfsMount3TUmntall *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0;
       +        return a;
       +}
       +int
       +nfsmount3tumntallpack(uchar *a, uchar *ea, uchar **pa, NfsMount3TUmntall *x)
       +{
       +        USED(ea);
       +        USED(x);
       +        *pa = a;
       +        return 0;
       +}
       +int
       +nfsmount3tumntallunpack(uchar *a, uchar *ea, uchar **pa, NfsMount3TUmntall *x)
       +{
       +        USED(ea);
       +        USED(x);
       +        *pa = a;
       +        return 0;
       +}
       +void
       +nfsmount3rumntallprint(Fmt *fmt, NfsMount3RUmntall *x)
       +{
       +        USED(x);
       +        fmtprint(fmt, "%s\n", "NfsMount3RUmntall");
       +}
       +uint
       +nfsmount3rumntallsize(NfsMount3RUmntall *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0;
       +        return a;
       +}
       +int
       +nfsmount3rumntallpack(uchar *a, uchar *ea, uchar **pa, NfsMount3RUmntall *x)
       +{
       +        USED(ea);
       +        USED(x);
       +        *pa = a;
       +        return 0;
       +}
       +int
       +nfsmount3rumntallunpack(uchar *a, uchar *ea, uchar **pa, NfsMount3RUmntall *x)
       +{
       +        USED(ea);
       +        USED(x);
       +        *pa = a;
       +        return 0;
       +}
       +void
       +nfsmount3texportprint(Fmt *fmt, NfsMount3TExport *x)
       +{
       +        USED(x);
       +        fmtprint(fmt, "%s\n", "NfsMount3TExport");
       +}
       +uint
       +nfsmount3texportsize(NfsMount3TExport *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0;
       +        return a;
       +}
       +int
       +nfsmount3texportpack(uchar *a, uchar *ea, uchar **pa, NfsMount3TExport *x)
       +{
       +        USED(ea);
       +        USED(x);
       +        *pa = a;
       +        return 0;
       +}
       +int
       +nfsmount3texportunpack(uchar *a, uchar *ea, uchar **pa, NfsMount3TExport *x)
       +{
       +        USED(ea);
       +        USED(x);
       +        *pa = a;
       +        return 0;
       +}
       +void
       +nfsmount3rexportprint(Fmt *fmt, NfsMount3RExport *x)
       +{
       +        USED(x);
       +        fmtprint(fmt, "%s\n", "NfsMount3RExport");
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfsmount3rexportsize(NfsMount3RExport *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0;
       +        a += x->count;
       +        a += 4;        /* end of export list */
       +        return a;
       +}
       +int
       +nfsmount3rexportpack(uchar *a, uchar *ea, uchar **pa, NfsMount3RExport *x)
       +{
       +        u1int zero;
       +
       +        zero = 0;
       +        if(a+x->count > ea) goto Err;
       +        memmove(a, x->data, x->count);
       +        a += x->count;
       +        if(sunuint1pack(a, ea, &a, &zero) < 0)
       +                goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfsmount3rexportunpack(uchar *a, uchar *ea, uchar **pa, NfsMount3RExport *x)
       +{
       +        int ng, ne;
       +        uchar *oa;
       +        u1int u1;
       +        u32int u32;
       +
       +        oa = a;
       +        ng = 0;
       +        for(ne=0;; ne++){
       +                if(sunuint1unpack(a, ea, &a, &u1) < 0)
       +                        goto Err;
       +                if(u1 == 0)
       +                        break;
       +                if(sunuint32unpack(a, ea, &a, &u32) < 0
       +                || (a += (u32+3)&~3) >= ea)
       +                        goto Err;
       +                for(;; ng++){
       +                        if(sunuint1unpack(a, ea, &a, &u1) < 0)
       +                                goto Err;
       +                        if(u1 == 0)
       +                                break;
       +                        if(sunuint32unpack(a, ea, &a, &u32) < 0
       +                        || (a += (u32+3)&~3) >= ea)
       +                                goto Err;
       +                }
       +        }
       +        x->data = oa;
       +        x->count = (a-4) - oa;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +uint
       +nfsmount3exportgroupsize(uchar *a)
       +{
       +        int ng;
       +        u1int have;
       +        u32int n;
       +
       +        a += 4;
       +        sunuint32unpack(a, a+4, &a, &n);
       +        a += (n+3)&~3;
       +        ng = 0;
       +        for(;;){
       +                sunuint1unpack(a, a+4, &a, &have);
       +                if(have == 0)
       +                        break;
       +                ng++;
       +                sunuint32unpack(a, a+4, &a, &n);
       +                a += (n+3)&~3;
       +        }
       +        return ng;
       +}
       +int
       +nfsmount3exportunpack(uchar *a, uchar *ea, uchar **pa, char **gp, char ***pgp, NfsMount3Export *x)
       +{
       +        int ng;
       +        u1int u1;
       +
       +        if(sunuint1unpack(a, ea, &a, &u1) < 0 || u1 != 1) goto Err;
       +        if(sunstringunpack(a, ea, &a, &x->path, NfsMount3MaxPathSize) < 0) goto Err;
       +        x->g = gp;
       +        ng = 0;
       +        for(;;){
       +                if(sunuint1unpack(a, ea, &a, &u1) < 0) goto Err;
       +                if(u1 == 0)
       +                        break;
       +                if(sunstringunpack(a, ea, &a, &gp[ng++], NfsMount3MaxNameSize) < 0) goto Err;
       +        }
       +        x->ng = ng;
       +        *pgp = gp+ng;
       +        *pa = a;
       +        return 0;
       +
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +uint
       +nfsmount3exportsize(NfsMount3Export *x)
       +{
       +        int i;
       +        uint a;
       +
       +        a = 4 + sunstringsize(x->path);
       +        for(i=0; i<x->ng; i++)
       +                a += 4 + sunstringsize(x->g[i]);
       +        a += 4;
       +        return a;
       +}
       +int
       +nfsmount3exportpack(uchar *a, uchar *ea, uchar **pa, NfsMount3Export *x)
       +{
       +        int i;
       +        u1int u1;
       +
       +        u1 = 1;
       +        if(sunuint1pack(a, ea, &a, &u1) < 0) goto Err;
       +        if(sunstringpack(a, ea, &a, &x->path, NfsMount3MaxPathSize) < 0) goto Err;
       +        for(i=0; i<x->ng; i++){
       +                if(sunuint1pack(a, ea, &a, &u1) < 0) goto Err;
       +                if(sunstringpack(a, ea, &a, &x->g[i], NfsMount3MaxNameSize) < 0) goto Err;
       +        }
       +        u1 = 0;
       +        if(sunuint1pack(a, ea, &a, &u1) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +
       +typedef int (*P)(uchar*, uchar*, uchar**, SunCall*);
       +typedef void (*F)(Fmt*, SunCall*);
       +typedef uint (*S)(SunCall*);
       +
       +static SunProc proc3[] = {
       +        (P)nfsmount3tnullpack, (P)nfsmount3tnullunpack, (S)nfsmount3tnullsize, (F)nfsmount3tnullprint, sizeof(NfsMount3TNull),
       +        (P)nfsmount3rnullpack, (P)nfsmount3rnullunpack, (S)nfsmount3rnullsize, (F)nfsmount3rnullprint, sizeof(NfsMount3RNull),
       +        (P)nfsmount3tmntpack, (P)nfsmount3tmntunpack, (S)nfsmount3tmntsize, (F)nfsmount3tmntprint, sizeof(NfsMount3TMnt),
       +        (P)nfsmount3rmntpack, (P)nfsmount3rmntunpack, (S)nfsmount3rmntsize, (F)nfsmount3rmntprint, sizeof(NfsMount3RMnt),
       +        (P)nfsmount3tdumppack, (P)nfsmount3tdumpunpack, (S)nfsmount3tdumpsize, (F)nfsmount3tdumpprint, sizeof(NfsMount3TDump),
       +        (P)nfsmount3rdumppack, (P)nfsmount3rdumpunpack, (S)nfsmount3rdumpsize, (F)nfsmount3rdumpprint, sizeof(NfsMount3RDump),
       +        (P)nfsmount3tumntpack, (P)nfsmount3tumntunpack, (S)nfsmount3tumntsize, (F)nfsmount3tumntprint, sizeof(NfsMount3TUmnt),
       +        (P)nfsmount3rumntpack, (P)nfsmount3rumntunpack, (S)nfsmount3rumntsize, (F)nfsmount3rumntprint, sizeof(NfsMount3RUmnt),
       +        (P)nfsmount3tumntallpack, (P)nfsmount3tumntallunpack, (S)nfsmount3tumntallsize, (F)nfsmount3tumntallprint, sizeof(NfsMount3TUmntall),
       +        (P)nfsmount3rumntallpack, (P)nfsmount3rumntallunpack, (S)nfsmount3rumntallsize, (F)nfsmount3rumntallprint, sizeof(NfsMount3RUmntall),
       +        (P)nfsmount3texportpack, (P)nfsmount3texportunpack, (S)nfsmount3texportsize, (F)nfsmount3texportprint, sizeof(NfsMount3TExport),
       +        (P)nfsmount3rexportpack, (P)nfsmount3rexportunpack, (S)nfsmount3rexportsize, (F)nfsmount3rexportprint, sizeof(NfsMount3RExport),
       +};
       +
       +static SunProc proc1[] = {
       +        (P)nfsmount3tnullpack, (P)nfsmount3tnullunpack, (S)nfsmount3tnullsize, (F)nfsmount3tnullprint, sizeof(NfsMount3TNull),
       +        (P)nfsmount3rnullpack, (P)nfsmount3rnullunpack, (S)nfsmount3rnullsize, (F)nfsmount3rnullprint, sizeof(NfsMount3RNull),
       +        (P)nfsmount3tmntpack, (P)nfsmount3tmntunpack, (S)nfsmount3tmntsize, (F)nfsmount3tmntprint, sizeof(NfsMount3TMnt),
       +        (P)nfsmount1rmntpack, (P)nfsmount1rmntunpack, (S)nfsmount1rmntsize, (F)nfsmount3rmntprint, sizeof(NfsMount3RMnt),
       +        (P)nfsmount3tdumppack, (P)nfsmount3tdumpunpack, (S)nfsmount3tdumpsize, (F)nfsmount3tdumpprint, sizeof(NfsMount3TDump),
       +        (P)nfsmount3rdumppack, (P)nfsmount3rdumpunpack, (S)nfsmount3rdumpsize, (F)nfsmount3rdumpprint, sizeof(NfsMount3RDump),
       +        (P)nfsmount3tumntpack, (P)nfsmount3tumntunpack, (S)nfsmount3tumntsize, (F)nfsmount3tumntprint, sizeof(NfsMount3TUmnt),
       +        (P)nfsmount3rumntpack, (P)nfsmount3rumntunpack, (S)nfsmount3rumntsize, (F)nfsmount3rumntprint, sizeof(NfsMount3RUmnt),
       +        (P)nfsmount3tumntallpack, (P)nfsmount3tumntallunpack, (S)nfsmount3tumntallsize, (F)nfsmount3tumntallprint, sizeof(NfsMount3TUmntall),
       +        (P)nfsmount3rumntallpack, (P)nfsmount3rumntallunpack, (S)nfsmount3rumntallsize, (F)nfsmount3rumntallprint, sizeof(NfsMount3RUmntall),
       +        (P)nfsmount3texportpack, (P)nfsmount3texportunpack, (S)nfsmount3texportsize, (F)nfsmount3texportprint, sizeof(NfsMount3TExport),
       +        (P)nfsmount3rexportpack, (P)nfsmount3rexportunpack, (S)nfsmount3rexportsize, (F)nfsmount3rexportprint, sizeof(NfsMount3RExport),
       +};
       +
       +SunProg nfsmount3prog = 
       +{
       +        NfsMount3Program,
       +        NfsMount3Version,
       +        proc3,
       +        nelem(proc3),
       +};
       +
       +SunProg nfsmount1prog =
       +{
       +        NfsMount1Program,
       +        NfsMount1Version,
       +        proc1,
       +        nelem(proc1),
       +};
 (DIR) diff --git a/src/libsunrpc/net.c b/src/libsunrpc/net.c
       t@@ -0,0 +1,57 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <thread.h>
       +#include <sunrpc.h>
       +
       +typedef struct Arg Arg;
       +struct Arg
       +{
       +        int fd;
       +        char adir[40];
       +        SunSrv *srv;
       +};
       +
       +static void
       +sunnetlisten(void *v)
       +{
       +        int fd, lcfd;
       +        char ldir[40];
       +        Arg *a = v;
       +
       +        for(;;){
       +                lcfd = listen(a->adir, ldir);
       +                if(lcfd < 0)
       +                        break;
       +                fd = accept(lcfd, ldir);
       +                close(lcfd);
       +                if(fd < 0)
       +                        continue;
       +                if(!sunsrvfd(a->srv, fd))
       +                        close(fd);
       +        }
       +        free(a);
       +        close(a->fd);
       +}
       +
       +int
       +sunsrvnet(SunSrv *srv, char *addr)
       +{
       +        Arg *a;
       +
       +        a = emalloc(sizeof(Arg));
       +        if((a->fd = announce(addr, a->adir)) < 0)
       +                return -1;
       +        a->srv = srv;
       +
       +        proccreate(sunnetlisten, a, SunStackSize);
       +        return 0;
       +}
       +
       +int
       +sunsrvannounce(SunSrv *srv, char *addr)
       +{
       +        if(strstr(addr, "udp!"))
       +                return sunsrvudp(srv, addr);
       +        else
       +                return sunsrvnet(srv, addr);
       +}
 (DIR) diff --git a/src/libsunrpc/nfs3.c b/src/libsunrpc/nfs3.c
       t@@ -0,0 +1,4045 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <thread.h>
       +#include <sunrpc.h>
       +#include <nfs3.h>
       +
       +char*
       +nfs3statusstr(Nfs3Status x)
       +{
       +        switch(x){
       +        case Nfs3Ok:
       +                return "Nfs3Ok";
       +        case Nfs3ErrNotOwner:
       +                return "Nfs3ErrNotOwner";
       +        case Nfs3ErrNoEnt:
       +                return "Nfs3ErrNoEnt";
       +        case Nfs3ErrNoMem:
       +                return "Nfs3ErrNoMem";
       +        case Nfs3ErrIo:
       +                return "Nfs3ErrIo";
       +        case Nfs3ErrNxio:
       +                return "Nfs3ErrNxio";
       +        case Nfs3ErrAcces:
       +                return "Nfs3ErrAcces";
       +        case Nfs3ErrExist:
       +                return "Nfs3ErrExist";
       +        case Nfs3ErrXDev:
       +                return "Nfs3ErrXDev";
       +        case Nfs3ErrNoDev:
       +                return "Nfs3ErrNoDev";
       +        case Nfs3ErrNotDir:
       +                return "Nfs3ErrNotDir";
       +        case Nfs3ErrIsDir:
       +                return "Nfs3ErrIsDir";
       +        case Nfs3ErrInval:
       +                return "Nfs3ErrInval";
       +        case Nfs3ErrFbig:
       +                return "Nfs3ErrFbig";
       +        case Nfs3ErrNoSpc:
       +                return "Nfs3ErrNoSpc";
       +        case Nfs3ErrRoFs:
       +                return "Nfs3ErrRoFs";
       +        case Nfs3ErrMLink:
       +                return "Nfs3ErrMLink";
       +        case Nfs3ErrNameTooLong:
       +                return "Nfs3ErrNameTooLong";
       +        case Nfs3ErrNotEmpty:
       +                return "Nfs3ErrNotEmpty";
       +        case Nfs3ErrDQuot:
       +                return "Nfs3ErrDQuot";
       +        case Nfs3ErrStale:
       +                return "Nfs3ErrStale";
       +        case Nfs3ErrRemote:
       +                return "Nfs3ErrRemote";
       +        case Nfs3ErrBadHandle:
       +                return "Nfs3ErrBadHandle";
       +        case Nfs3ErrNotSync:
       +                return "Nfs3ErrNotSync";
       +        case Nfs3ErrBadCookie:
       +                return "Nfs3ErrBadCookie";
       +        case Nfs3ErrNotSupp:
       +                return "Nfs3ErrNotSupp";
       +        case Nfs3ErrTooSmall:
       +                return "Nfs3ErrTooSmall";
       +        case Nfs3ErrServerFault:
       +                return "Nfs3ErrServerFault";
       +        case Nfs3ErrBadType:
       +                return "Nfs3ErrBadType";
       +        case Nfs3ErrJukebox:
       +                return "Nfs3ErrJukebox";
       +        case Nfs3ErrFprintNotFound:
       +                return "Nfs3ErrFprintNotFound";
       +        case Nfs3ErrAborted:
       +                return "Nfs3ErrAborted";
       +        default:
       +                return "unknown";
       +        }
       +}
       +
       +static struct {
       +        SunStatus status;
       +        char *msg;
       +} etab[] = {
       +        Nfs3ErrNotOwner,        "not owner",
       +        Nfs3ErrNoEnt,                "directory entry not found",
       +        Nfs3ErrIo,                        "i/o error",
       +        Nfs3ErrNxio,                "no such device",
       +        Nfs3ErrNoMem,        "out of memory",
       +        Nfs3ErrAcces,                "access denied",
       +        Nfs3ErrExist,                "file or directory exists",
       +        Nfs3ErrXDev,                "cross-device operation",
       +        Nfs3ErrNoDev,                "no such device",
       +        Nfs3ErrNotDir,                "not a directory",
       +        Nfs3ErrIsDir,                "is a directory",
       +        Nfs3ErrInval,                "invalid arguments",
       +        Nfs3ErrFbig,                "file too big",
       +        Nfs3ErrNoSpc,                "no space left on device",
       +        Nfs3ErrRoFs,                "read-only file system",
       +        Nfs3ErrMLink,                "too many links",
       +        Nfs3ErrNameTooLong,        "name too long",
       +        Nfs3ErrNotEmpty,        "directory not empty",
       +        Nfs3ErrDQuot,                "dquot",
       +        Nfs3ErrStale,                "stale handle",
       +        Nfs3ErrRemote,        "remote error",
       +        Nfs3ErrBadHandle,        "bad handle",
       +        Nfs3ErrNotSync,        "out of sync with server",
       +        Nfs3ErrBadCookie,        "bad cookie",
       +        Nfs3ErrNotSupp,        "not supported",
       +        Nfs3ErrTooSmall,        "too small",
       +        Nfs3ErrServerFault,        "server fault",
       +        Nfs3ErrBadType,        "bad type",
       +        Nfs3ErrJukebox,        "jukebox -- try again later",
       +        Nfs3ErrFprintNotFound,        "fprint not found",
       +        Nfs3ErrAborted,        "aborted",
       +};
       +
       +void
       +nfs3errstr(SunStatus status)
       +{
       +        int i;
       +
       +        for(i=0; i<nelem(etab); i++){
       +                if(etab[i].status == status){
       +                        werrstr(etab[i].msg);
       +                        return;
       +                }
       +        }
       +        werrstr("unknown nfs3 error %d", (int)status);
       +}
       +
       +char*
       +nfs3filetypestr(Nfs3FileType x)
       +{
       +        switch(x){
       +        case Nfs3FileReg:
       +                return "Nfs3FileReg";
       +        case Nfs3FileDir:
       +                return "Nfs3FileDir";
       +        case Nfs3FileBlock:
       +                return "Nfs3FileBlock";
       +        case Nfs3FileChar:
       +                return "Nfs3FileChar";
       +        case Nfs3FileSymlink:
       +                return "Nfs3FileSymlink";
       +        case Nfs3FileSocket:
       +                return "Nfs3FileSocket";
       +        case Nfs3FileFifo:
       +                return "Nfs3FileFifo";
       +        default:
       +                return "unknown";
       +        }
       +}
       +
       +void
       +nfs3handleprint(Fmt *fmt, Nfs3Handle *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3Handle");
       +        fmtprint(fmt, "\t%s=", "handle");
       +        if(x->len > 64)
       +                fmtprint(fmt, "%.*H... (%d)", 64, x->h, x->len);
       +        else
       +                fmtprint(fmt, "%.*H", x->len, x->h);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3handlesize(Nfs3Handle *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + sunvaropaquesize(x->len);
       +        return a;
       +}
       +int
       +nfs3handlepack(uchar *a, uchar *ea, uchar **pa, Nfs3Handle *x)
       +{
       +        if(x->len > Nfs3MaxHandleSize || sunuint32pack(a, ea, &a, &x->len) < 0
       +        || sunfixedopaquepack(a, ea, &a, x->h, x->len) < 0)
       +                goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3handleunpack(uchar *a, uchar *ea, uchar **pa, Nfs3Handle *x)
       +{
       +        uchar *ha;
       +        u32int n;
       +
       +        if(sunuint32unpack(a, ea, &a, &n) < 0 || n > Nfs3MaxHandleSize)
       +                goto Err;
       +        ha = a;
       +        a += (n+3)&~3;
       +        if(a > ea)
       +                goto Err;
       +        memmove(x->h, ha, n);
       +        x->len = n;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3timeprint(Fmt *fmt, Nfs3Time *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3Time");
       +        fmtprint(fmt, "\t%s=", "sec");
       +        fmtprint(fmt, "%ud", x->sec);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "nsec");
       +        fmtprint(fmt, "%ud", x->nsec);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3timesize(Nfs3Time *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4 + 4;
       +        return a;
       +}
       +int
       +nfs3timepack(uchar *a, uchar *ea, uchar **pa, Nfs3Time *x)
       +{
       +        if(sunuint32pack(a, ea, &a, &x->sec) < 0) goto Err;
       +        if(sunuint32pack(a, ea, &a, &x->nsec) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3timeunpack(uchar *a, uchar *ea, uchar **pa, Nfs3Time *x)
       +{
       +        if(sunuint32unpack(a, ea, &a, &x->sec) < 0) goto Err;
       +        if(sunuint32unpack(a, ea, &a, &x->nsec) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3attrprint(Fmt *fmt, Nfs3Attr *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3Attr");
       +        fmtprint(fmt, "\t%s=", "type");
       +        fmtprint(fmt, "%s", nfs3filetypestr(x->type));
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "mode");
       +        fmtprint(fmt, "%ud", x->mode);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "nlink");
       +        fmtprint(fmt, "%ud", x->nlink);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "uid");
       +        fmtprint(fmt, "%ud", x->uid);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "gid");
       +        fmtprint(fmt, "%ud", x->gid);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "size");
       +        fmtprint(fmt, "%llud", x->size);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "used");
       +        fmtprint(fmt, "%llud", x->used);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "major");
       +        fmtprint(fmt, "%ud", x->major);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "minor");
       +        fmtprint(fmt, "%ud", x->minor);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "fsid");
       +        fmtprint(fmt, "%llud", x->fsid);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "fileid");
       +        fmtprint(fmt, "%llud", x->fileid);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "atime");
       +        nfs3timeprint(fmt, &x->atime);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "mtime");
       +        nfs3timeprint(fmt, &x->mtime);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "ctime");
       +        nfs3timeprint(fmt, &x->ctime);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3attrsize(Nfs3Attr *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4 + 4 + 4 + 4 + 4 + 8 + 8 + 4 + 4 + 8 + 8 + nfs3timesize(&x->atime) + nfs3timesize(&x->mtime) + nfs3timesize(&x->ctime);
       +        return a;
       +}
       +int
       +nfs3attrpack(uchar *a, uchar *ea, uchar **pa, Nfs3Attr *x)
       +{
       +        int i;
       +
       +        if(i=x->type, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        if(sunuint32pack(a, ea, &a, &x->mode) < 0) goto Err;
       +        if(sunuint32pack(a, ea, &a, &x->nlink) < 0) goto Err;
       +        if(sunuint32pack(a, ea, &a, &x->uid) < 0) goto Err;
       +        if(sunuint32pack(a, ea, &a, &x->gid) < 0) goto Err;
       +        if(sunuint64pack(a, ea, &a, &x->size) < 0) goto Err;
       +        if(sunuint64pack(a, ea, &a, &x->used) < 0) goto Err;
       +        if(sunuint32pack(a, ea, &a, &x->major) < 0) goto Err;
       +        if(sunuint32pack(a, ea, &a, &x->minor) < 0) goto Err;
       +        if(sunuint64pack(a, ea, &a, &x->fsid) < 0) goto Err;
       +        if(sunuint64pack(a, ea, &a, &x->fileid) < 0) goto Err;
       +        if(nfs3timepack(a, ea, &a, &x->atime) < 0) goto Err;
       +        if(nfs3timepack(a, ea, &a, &x->mtime) < 0) goto Err;
       +        if(nfs3timepack(a, ea, &a, &x->ctime) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3attrunpack(uchar *a, uchar *ea, uchar **pa, Nfs3Attr *x)
       +{
       +        int i;
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->type = i;
       +        if(sunuint32unpack(a, ea, &a, &x->mode) < 0) goto Err;
       +        if(sunuint32unpack(a, ea, &a, &x->nlink) < 0) goto Err;
       +        if(sunuint32unpack(a, ea, &a, &x->uid) < 0) goto Err;
       +        if(sunuint32unpack(a, ea, &a, &x->gid) < 0) goto Err;
       +        if(sunuint64unpack(a, ea, &a, &x->size) < 0) goto Err;
       +        if(sunuint64unpack(a, ea, &a, &x->used) < 0) goto Err;
       +        if(sunuint32unpack(a, ea, &a, &x->major) < 0) goto Err;
       +        if(sunuint32unpack(a, ea, &a, &x->minor) < 0) goto Err;
       +        if(sunuint64unpack(a, ea, &a, &x->fsid) < 0) goto Err;
       +        if(sunuint64unpack(a, ea, &a, &x->fileid) < 0) goto Err;
       +        if(nfs3timeunpack(a, ea, &a, &x->atime) < 0) goto Err;
       +        if(nfs3timeunpack(a, ea, &a, &x->mtime) < 0) goto Err;
       +        if(nfs3timeunpack(a, ea, &a, &x->ctime) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3wccattrprint(Fmt *fmt, Nfs3WccAttr *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3WccAttr");
       +        fmtprint(fmt, "\t%s=", "size");
       +        fmtprint(fmt, "%llud", x->size);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "mtime");
       +        nfs3timeprint(fmt, &x->mtime);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "ctime");
       +        nfs3timeprint(fmt, &x->ctime);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3wccattrsize(Nfs3WccAttr *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 8 + nfs3timesize(&x->mtime) + nfs3timesize(&x->ctime);
       +        return a;
       +}
       +int
       +nfs3wccattrpack(uchar *a, uchar *ea, uchar **pa, Nfs3WccAttr *x)
       +{
       +        if(sunuint64pack(a, ea, &a, &x->size) < 0) goto Err;
       +        if(nfs3timepack(a, ea, &a, &x->mtime) < 0) goto Err;
       +        if(nfs3timepack(a, ea, &a, &x->ctime) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3wccattrunpack(uchar *a, uchar *ea, uchar **pa, Nfs3WccAttr *x)
       +{
       +        if(sunuint64unpack(a, ea, &a, &x->size) < 0) goto Err;
       +        if(nfs3timeunpack(a, ea, &a, &x->mtime) < 0) goto Err;
       +        if(nfs3timeunpack(a, ea, &a, &x->ctime) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3wccprint(Fmt *fmt, Nfs3Wcc *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3Wcc");
       +        fmtprint(fmt, "\t%s=", "haveWccAttr");
       +        fmtprint(fmt, "%d", x->haveWccAttr);
       +        fmtprint(fmt, "\n");
       +        switch(x->haveWccAttr){
       +        case 1:
       +                fmtprint(fmt, "\t%s=", "wccAttr");
       +                nfs3wccattrprint(fmt, &x->wccAttr);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +        fmtprint(fmt, "\t%s=", "haveAttr");
       +        fmtprint(fmt, "%d", x->haveAttr);
       +        fmtprint(fmt, "\n");
       +        switch(x->haveAttr){
       +        case 1:
       +                fmtprint(fmt, "\t%s=", "attr");
       +                nfs3attrprint(fmt, &x->attr);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +}
       +uint
       +nfs3wccsize(Nfs3Wcc *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4;
       +        switch(x->haveWccAttr){
       +        case 1:
       +                a = a + nfs3wccattrsize(&x->wccAttr);
       +                break;
       +        }
       +        a = a + 4;
       +        switch(x->haveAttr){
       +        case 1:
       +                a = a + nfs3attrsize(&x->attr);
       +                break;
       +        }
       +        return a;
       +}
       +int
       +nfs3wccpack(uchar *a, uchar *ea, uchar **pa, Nfs3Wcc *x)
       +{
       +        if(sunuint1pack(a, ea, &a, &x->haveWccAttr) < 0) goto Err;
       +        switch(x->haveWccAttr){
       +        case 1:
       +                if(nfs3wccattrpack(a, ea, &a, &x->wccAttr) < 0) goto Err;
       +                break;
       +        }
       +        if(sunuint1pack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +        switch(x->haveAttr){
       +        case 1:
       +                if(nfs3attrpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3wccunpack(uchar *a, uchar *ea, uchar **pa, Nfs3Wcc *x)
       +{
       +        if(sunuint1unpack(a, ea, &a, &x->haveWccAttr) < 0) goto Err;
       +        switch(x->haveWccAttr){
       +        case 1:
       +                if(nfs3wccattrunpack(a, ea, &a, &x->wccAttr) < 0) goto Err;
       +                break;
       +        }
       +        if(sunuint1unpack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +        switch(x->haveAttr){
       +        case 1:
       +                if(nfs3attrunpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +char*
       +nfs3settimestr(Nfs3SetTime x)
       +{
       +        switch(x){
       +        case Nfs3SetTimeDont:
       +                return "Nfs3SetTimeDont";
       +        case Nfs3SetTimeServer:
       +                return "Nfs3SetTimeServer";
       +        case Nfs3SetTimeClient:
       +                return "Nfs3SetTimeClient";
       +        default:
       +                return "unknown";
       +        }
       +}
       +
       +void
       +nfs3setattrprint(Fmt *fmt, Nfs3SetAttr *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3SetAttr");
       +        fmtprint(fmt, "\t%s=", "setMode");
       +        fmtprint(fmt, "%d", x->setMode);
       +        fmtprint(fmt, "\n");
       +        switch(x->setMode){
       +        case 1:
       +                fmtprint(fmt, "\t%s=", "mode");
       +                fmtprint(fmt, "%ud", x->mode);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +        fmtprint(fmt, "\t%s=", "setUid");
       +        fmtprint(fmt, "%d", x->setUid);
       +        fmtprint(fmt, "\n");
       +        switch(x->setUid){
       +        case 1:
       +                fmtprint(fmt, "\t%s=", "uid");
       +                fmtprint(fmt, "%ud", x->uid);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +        fmtprint(fmt, "\t%s=", "setGid");
       +        fmtprint(fmt, "%d", x->setGid);
       +        fmtprint(fmt, "\n");
       +        switch(x->setGid){
       +        case 1:
       +                fmtprint(fmt, "\t%s=", "gid");
       +                fmtprint(fmt, "%ud", x->gid);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +        fmtprint(fmt, "\t%s=", "setSize");
       +        fmtprint(fmt, "%d", x->setSize);
       +        fmtprint(fmt, "\n");
       +        switch(x->setSize){
       +        case 1:
       +                fmtprint(fmt, "\t%s=", "size");
       +                fmtprint(fmt, "%llud", x->size);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +        fmtprint(fmt, "\t%s=", "setAtime");
       +        fmtprint(fmt, "%s", nfs3settimestr(x->setAtime));
       +        fmtprint(fmt, "\n");
       +        switch(x->setAtime){
       +        case Nfs3SetTimeClient:
       +                fmtprint(fmt, "\t%s=", "atime");
       +                nfs3timeprint(fmt, &x->atime);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +        fmtprint(fmt, "\t%s=", "setMtime");
       +        fmtprint(fmt, "%s", nfs3settimestr(x->setMtime));
       +        fmtprint(fmt, "\n");
       +        switch(x->setMtime){
       +        case Nfs3SetTimeClient:
       +                fmtprint(fmt, "\t%s=", "mtime");
       +                nfs3timeprint(fmt, &x->mtime);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +}
       +uint
       +nfs3setattrsize(Nfs3SetAttr *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4;
       +        switch(x->setMode){
       +        case 1:
       +                a = a + 4;
       +                break;
       +        }
       +        a = a + 4;
       +        switch(x->setUid){
       +        case 1:
       +                a = a + 4;
       +                break;
       +        }
       +        a = a + 4;
       +        switch(x->setGid){
       +        case 1:
       +                a = a + 4;
       +                break;
       +        }
       +        a = a + 4;
       +        switch(x->setSize){
       +        case 1:
       +                a = a + 8;
       +                break;
       +        }
       +        a = a + 4;
       +        switch(x->setAtime){
       +        case Nfs3SetTimeClient:
       +                a = a + nfs3timesize(&x->atime);
       +                break;
       +        }
       +        a = a + 4;
       +        switch(x->setMtime){
       +        case Nfs3SetTimeClient:
       +                a = a + nfs3timesize(&x->mtime);
       +                break;
       +        }
       +        return a;
       +}
       +int
       +nfs3setattrpack(uchar *a, uchar *ea, uchar **pa, Nfs3SetAttr *x)
       +{
       +        int i;
       +
       +        if(sunuint1pack(a, ea, &a, &x->setMode) < 0) goto Err;
       +        switch(x->setMode){
       +        case 1:
       +                if(sunuint32pack(a, ea, &a, &x->mode) < 0) goto Err;
       +                break;
       +        }
       +        if(sunuint1pack(a, ea, &a, &x->setUid) < 0) goto Err;
       +        switch(x->setUid){
       +        case 1:
       +                if(sunuint32pack(a, ea, &a, &x->uid) < 0) goto Err;
       +                break;
       +        }
       +        if(sunuint1pack(a, ea, &a, &x->setGid) < 0) goto Err;
       +        switch(x->setGid){
       +        case 1:
       +                if(sunuint32pack(a, ea, &a, &x->gid) < 0) goto Err;
       +                break;
       +        }
       +        if(sunuint1pack(a, ea, &a, &x->setSize) < 0) goto Err;
       +        switch(x->setSize){
       +        case 1:
       +                if(sunuint64pack(a, ea, &a, &x->size) < 0) goto Err;
       +                break;
       +        }
       +        if(i=x->setAtime, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        switch(x->setAtime){
       +        case Nfs3SetTimeClient:
       +                if(nfs3timepack(a, ea, &a, &x->atime) < 0) goto Err;
       +                break;
       +        }
       +        if(i=x->setMtime, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        switch(x->setMtime){
       +        case Nfs3SetTimeClient:
       +                if(nfs3timepack(a, ea, &a, &x->mtime) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3setattrunpack(uchar *a, uchar *ea, uchar **pa, Nfs3SetAttr *x)
       +{
       +        int i;
       +
       +        if(sunuint1unpack(a, ea, &a, &x->setMode) < 0) goto Err;
       +        switch(x->setMode){
       +        case 1:
       +                if(sunuint32unpack(a, ea, &a, &x->mode) < 0) goto Err;
       +                break;
       +        }
       +        if(sunuint1unpack(a, ea, &a, &x->setUid) < 0) goto Err;
       +        switch(x->setUid){
       +        case 1:
       +                if(sunuint32unpack(a, ea, &a, &x->uid) < 0) goto Err;
       +                break;
       +        }
       +        if(sunuint1unpack(a, ea, &a, &x->setGid) < 0) goto Err;
       +        switch(x->setGid){
       +        case 1:
       +                if(sunuint32unpack(a, ea, &a, &x->gid) < 0) goto Err;
       +                break;
       +        }
       +        if(sunuint1unpack(a, ea, &a, &x->setSize) < 0) goto Err;
       +        switch(x->setSize){
       +        case 1:
       +                if(sunuint64unpack(a, ea, &a, &x->size) < 0) goto Err;
       +                break;
       +        }
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->setAtime = i;
       +        switch(x->setAtime){
       +        case Nfs3SetTimeClient:
       +                if(nfs3timeunpack(a, ea, &a, &x->atime) < 0) goto Err;
       +                break;
       +        }
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->setMtime = i;
       +        switch(x->setMtime){
       +        case Nfs3SetTimeClient:
       +                if(nfs3timeunpack(a, ea, &a, &x->mtime) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3tnullprint(Fmt *fmt, Nfs3TNull *x)
       +{
       +        USED(x);
       +        fmtprint(fmt, "%s\n", "Nfs3TNull");
       +}
       +uint
       +nfs3tnullsize(Nfs3TNull *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0;
       +        return a;
       +}
       +int
       +nfs3tnullpack(uchar *a, uchar *ea, uchar **pa, Nfs3TNull *x)
       +{
       +        USED(x);
       +        USED(ea);
       +        *pa = a;
       +        return 0;
       +}
       +int
       +nfs3tnullunpack(uchar *a, uchar *ea, uchar **pa, Nfs3TNull *x)
       +{
       +        USED(x);
       +        USED(ea);
       +        *pa = a;
       +        return 0;
       +}
       +void
       +nfs3rnullprint(Fmt *fmt, Nfs3RNull *x)
       +{
       +        USED(x);
       +        fmtprint(fmt, "%s\n", "Nfs3RNull");
       +}
       +uint
       +nfs3rnullsize(Nfs3RNull *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0;
       +        return a;
       +}
       +int
       +nfs3rnullpack(uchar *a, uchar *ea, uchar **pa, Nfs3RNull *x)
       +{
       +        USED(ea);
       +        USED(x);
       +        *pa = a;
       +        return 0;
       +}
       +int
       +nfs3rnullunpack(uchar *a, uchar *ea, uchar **pa, Nfs3RNull *x)
       +{
       +        USED(ea);
       +        USED(x);
       +        *pa = a;
       +        return 0;
       +}
       +void
       +nfs3tgetattrprint(Fmt *fmt, Nfs3TGetattr *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3TGetattr");
       +        fmtprint(fmt, "\t%s=", "handle");
       +        nfs3handleprint(fmt, &x->handle);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3tgetattrsize(Nfs3TGetattr *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + nfs3handlesize(&x->handle);
       +        return a;
       +}
       +int
       +nfs3tgetattrpack(uchar *a, uchar *ea, uchar **pa, Nfs3TGetattr *x)
       +{
       +        if(nfs3handlepack(a, ea, &a, &x->handle) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3tgetattrunpack(uchar *a, uchar *ea, uchar **pa, Nfs3TGetattr *x)
       +{
       +        if(nfs3handleunpack(a, ea, &a, &x->handle) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3rgetattrprint(Fmt *fmt, Nfs3RGetattr *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3RGetattr");
       +        fmtprint(fmt, "\t%s=", "status");
       +        fmtprint(fmt, "%s", nfs3statusstr(x->status));
       +        fmtprint(fmt, "\n");
       +        switch(x->status){
       +        case Nfs3Ok:
       +                fmtprint(fmt, "\t%s=", "attr");
       +                nfs3attrprint(fmt, &x->attr);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +}
       +uint
       +nfs3rgetattrsize(Nfs3RGetattr *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4;
       +        switch(x->status){
       +        case Nfs3Ok:
       +                a = a + nfs3attrsize(&x->attr);
       +                break;
       +        }
       +        return a;
       +}
       +int
       +nfs3rgetattrpack(uchar *a, uchar *ea, uchar **pa, Nfs3RGetattr *x)
       +{
       +        int i;
       +
       +        if(i=x->status, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(nfs3attrpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3rgetattrunpack(uchar *a, uchar *ea, uchar **pa, Nfs3RGetattr *x)
       +{
       +        int i;
       +
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->status = i;
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(nfs3attrunpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3tsetattrprint(Fmt *fmt, Nfs3TSetattr *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3TSetattr");
       +        fmtprint(fmt, "\t%s=", "handle");
       +        nfs3handleprint(fmt, &x->handle);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "attr");
       +        nfs3setattrprint(fmt, &x->attr);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "checkCtime");
       +        fmtprint(fmt, "%d", x->checkCtime);
       +        fmtprint(fmt, "\n");
       +        switch(x->checkCtime){
       +        case 1:
       +                fmtprint(fmt, "\t%s=", "ctime");
       +                nfs3timeprint(fmt, &x->ctime);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +}
       +uint
       +nfs3tsetattrsize(Nfs3TSetattr *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + nfs3handlesize(&x->handle) + nfs3setattrsize(&x->attr) + 4;
       +        switch(x->checkCtime){
       +        case 1:
       +                a = a + nfs3timesize(&x->ctime);
       +                break;
       +        }
       +        return a;
       +}
       +int
       +nfs3tsetattrpack(uchar *a, uchar *ea, uchar **pa, Nfs3TSetattr *x)
       +{
       +        if(nfs3handlepack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(nfs3setattrpack(a, ea, &a, &x->attr) < 0) goto Err;
       +        if(sunuint1pack(a, ea, &a, &x->checkCtime) < 0) goto Err;
       +        switch(x->checkCtime){
       +        case 1:
       +                if(nfs3timepack(a, ea, &a, &x->ctime) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3tsetattrunpack(uchar *a, uchar *ea, uchar **pa, Nfs3TSetattr *x)
       +{
       +        if(nfs3handleunpack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(nfs3setattrunpack(a, ea, &a, &x->attr) < 0) goto Err;
       +        if(sunuint1unpack(a, ea, &a, &x->checkCtime) < 0) goto Err;
       +        switch(x->checkCtime){
       +        case 1:
       +                if(nfs3timeunpack(a, ea, &a, &x->ctime) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3rsetattrprint(Fmt *fmt, Nfs3RSetattr *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3RSetattr");
       +        fmtprint(fmt, "\t%s=", "status");
       +        fmtprint(fmt, "%s", nfs3statusstr(x->status));
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "wcc");
       +        nfs3wccprint(fmt, &x->wcc);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3rsetattrsize(Nfs3RSetattr *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4 + nfs3wccsize(&x->wcc);
       +        return a;
       +}
       +int
       +nfs3rsetattrpack(uchar *a, uchar *ea, uchar **pa, Nfs3RSetattr *x)
       +{
       +        int i;
       +
       +        if(i=x->status, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        if(nfs3wccpack(a, ea, &a, &x->wcc) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3rsetattrunpack(uchar *a, uchar *ea, uchar **pa, Nfs3RSetattr *x)
       +{
       +        int i;
       +
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->status = i;
       +        if(nfs3wccunpack(a, ea, &a, &x->wcc) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3tlookupprint(Fmt *fmt, Nfs3TLookup *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3TLookup");
       +        fmtprint(fmt, "\t%s=", "handle");
       +        nfs3handleprint(fmt, &x->handle);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "name");
       +        fmtprint(fmt, "\"%s\"", x->name);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3tlookupsize(Nfs3TLookup *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + nfs3handlesize(&x->handle) + sunstringsize(x->name);
       +        return a;
       +}
       +int
       +nfs3tlookuppack(uchar *a, uchar *ea, uchar **pa, Nfs3TLookup *x)
       +{
       +        if(nfs3handlepack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(sunstringpack(a, ea, &a, &x->name, -1) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3tlookupunpack(uchar *a, uchar *ea, uchar **pa, Nfs3TLookup *x)
       +{
       +        if(nfs3handleunpack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(sunstringunpack(a, ea, &a, &x->name, -1) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3rlookupprint(Fmt *fmt, Nfs3RLookup *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3RLookup");
       +        fmtprint(fmt, "\t%s=", "status");
       +        fmtprint(fmt, "%s", nfs3statusstr(x->status));
       +        fmtprint(fmt, "\n");
       +        switch(x->status){
       +        case Nfs3Ok:
       +                fmtprint(fmt, "\t%s=", "handle");
       +                nfs3handleprint(fmt, &x->handle);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "haveAttr");
       +                fmtprint(fmt, "%d", x->haveAttr);
       +                fmtprint(fmt, "\n");
       +                switch(x->haveAttr){
       +                case 1:
       +                        fmtprint(fmt, "\t%s=", "attr");
       +                        nfs3attrprint(fmt, &x->attr);
       +                        fmtprint(fmt, "\n");
       +                        break;
       +                }
       +                break;
       +        }
       +        fmtprint(fmt, "\t%s=", "haveDirAttr");
       +        fmtprint(fmt, "%d", x->haveDirAttr);
       +        fmtprint(fmt, "\n");
       +        switch(x->haveDirAttr){
       +        case 1:
       +                fmtprint(fmt, "\t%s=", "dirAttr");
       +                nfs3attrprint(fmt, &x->dirAttr);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +}
       +uint
       +nfs3rlookupsize(Nfs3RLookup *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4;
       +        switch(x->status){
       +        case Nfs3Ok:
       +                a = a + nfs3handlesize(&x->handle) + 4;
       +                switch(x->haveAttr){
       +                case 1:
       +                        a = a + nfs3attrsize(&x->attr);
       +                        break;
       +                }
       +                        break;
       +        }
       +        a = a + 4;
       +        switch(x->haveDirAttr){
       +        case 1:
       +                a = a + nfs3attrsize(&x->dirAttr);
       +                break;
       +        }
       +        return a;
       +}
       +int
       +nfs3rlookuppack(uchar *a, uchar *ea, uchar **pa, Nfs3RLookup *x)
       +{
       +        int i;
       +
       +        if(i=x->status, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(nfs3handlepack(a, ea, &a, &x->handle) < 0) goto Err;
       +                if(sunuint1pack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +                switch(x->haveAttr){
       +                case 1:
       +                        if(nfs3attrpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                        break;
       +                }
       +                break;
       +        }
       +        if(sunuint1pack(a, ea, &a, &x->haveDirAttr) < 0) goto Err;
       +        switch(x->haveDirAttr){
       +        case 1:
       +                if(nfs3attrpack(a, ea, &a, &x->dirAttr) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3rlookupunpack(uchar *a, uchar *ea, uchar **pa, Nfs3RLookup *x)
       +{
       +        int i;
       +
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->status = i;
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(nfs3handleunpack(a, ea, &a, &x->handle) < 0) goto Err;
       +                if(sunuint1unpack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +                switch(x->haveAttr){
       +                case 1:
       +                        if(nfs3attrunpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                        break;
       +                }
       +                break;
       +        }
       +        if(sunuint1unpack(a, ea, &a, &x->haveDirAttr) < 0) goto Err;
       +        switch(x->haveDirAttr){
       +        case 1:
       +                if(nfs3attrunpack(a, ea, &a, &x->dirAttr) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3taccessprint(Fmt *fmt, Nfs3TAccess *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3TAccess");
       +        fmtprint(fmt, "\t%s=", "handle");
       +        nfs3handleprint(fmt, &x->handle);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "access");
       +        fmtprint(fmt, "%ud", x->access);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3taccesssize(Nfs3TAccess *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + nfs3handlesize(&x->handle) + 4;
       +        return a;
       +}
       +int
       +nfs3taccesspack(uchar *a, uchar *ea, uchar **pa, Nfs3TAccess *x)
       +{
       +        if(nfs3handlepack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(sunuint32pack(a, ea, &a, &x->access) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3taccessunpack(uchar *a, uchar *ea, uchar **pa, Nfs3TAccess *x)
       +{
       +        if(nfs3handleunpack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(sunuint32unpack(a, ea, &a, &x->access) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3raccessprint(Fmt *fmt, Nfs3RAccess *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3RAccess");
       +        fmtprint(fmt, "\t%s=", "status");
       +        fmtprint(fmt, "%s", nfs3statusstr(x->status));
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "haveAttr");
       +        fmtprint(fmt, "%d", x->haveAttr);
       +        fmtprint(fmt, "\n");
       +        switch(x->haveAttr){
       +        case 1:
       +                fmtprint(fmt, "\t%s=", "attr");
       +                nfs3attrprint(fmt, &x->attr);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                fmtprint(fmt, "\t%s=", "access");
       +                fmtprint(fmt, "%ud", x->access);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +}
       +uint
       +nfs3raccesssize(Nfs3RAccess *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4 + 4;
       +        switch(x->haveAttr){
       +        case 1:
       +                a = a + nfs3attrsize(&x->attr);
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                a = a + 4;
       +                break;
       +        }
       +        return a;
       +}
       +int
       +nfs3raccesspack(uchar *a, uchar *ea, uchar **pa, Nfs3RAccess *x)
       +{
       +        int i;
       +
       +        if(i=x->status, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        if(sunuint1pack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +        switch(x->haveAttr){
       +        case 1:
       +                if(nfs3attrpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(sunuint32pack(a, ea, &a, &x->access) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3raccessunpack(uchar *a, uchar *ea, uchar **pa, Nfs3RAccess *x)
       +{
       +        int i;
       +
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->status = i;
       +        if(sunuint1unpack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +        switch(x->haveAttr){
       +        case 1:
       +                if(nfs3attrunpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(sunuint32unpack(a, ea, &a, &x->access) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3treadlinkprint(Fmt *fmt, Nfs3TReadlink *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3TReadlink");
       +        fmtprint(fmt, "\t%s=", "handle");
       +        nfs3handleprint(fmt, &x->handle);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3treadlinksize(Nfs3TReadlink *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + nfs3handlesize(&x->handle);
       +        return a;
       +}
       +int
       +nfs3treadlinkpack(uchar *a, uchar *ea, uchar **pa, Nfs3TReadlink *x)
       +{
       +        if(nfs3handlepack(a, ea, &a, &x->handle) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3treadlinkunpack(uchar *a, uchar *ea, uchar **pa, Nfs3TReadlink *x)
       +{
       +        if(nfs3handleunpack(a, ea, &a, &x->handle) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3rreadlinkprint(Fmt *fmt, Nfs3RReadlink *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3RReadlink");
       +        fmtprint(fmt, "\t%s=", "status");
       +        fmtprint(fmt, "%s", nfs3statusstr(x->status));
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "haveAttr");
       +        fmtprint(fmt, "%d", x->haveAttr);
       +        fmtprint(fmt, "\n");
       +        switch(x->haveAttr){
       +        case 1:
       +                fmtprint(fmt, "\t%s=", "attr");
       +                nfs3attrprint(fmt, &x->attr);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                fmtprint(fmt, "\t%s=", "data");
       +                fmtprint(fmt, "\"%s\"", x->data);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +}
       +uint
       +nfs3rreadlinksize(Nfs3RReadlink *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4 + 4;
       +        switch(x->haveAttr){
       +        case 1:
       +                a = a + nfs3attrsize(&x->attr);
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                a = a + sunstringsize(x->data);
       +                break;
       +        }
       +        return a;
       +}
       +int
       +nfs3rreadlinkpack(uchar *a, uchar *ea, uchar **pa, Nfs3RReadlink *x)
       +{
       +        int i;
       +
       +        if(i=x->status, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        if(sunuint1pack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +        switch(x->haveAttr){
       +        case 1:
       +                if(nfs3attrpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(sunstringpack(a, ea, &a, &x->data, -1) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3rreadlinkunpack(uchar *a, uchar *ea, uchar **pa, Nfs3RReadlink *x)
       +{
       +        int i;
       +
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->status = i;
       +        if(sunuint1unpack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +        switch(x->haveAttr){
       +        case 1:
       +                if(nfs3attrunpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(sunstringunpack(a, ea, &a, &x->data, -1) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3treadprint(Fmt *fmt, Nfs3TRead *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3TRead");
       +        fmtprint(fmt, "\t%s=", "handle");
       +        nfs3handleprint(fmt, &x->handle);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "offset");
       +        fmtprint(fmt, "%llud", x->offset);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "count");
       +        fmtprint(fmt, "%ud", x->count);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3treadsize(Nfs3TRead *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + nfs3handlesize(&x->handle) + 8 + 4;
       +        return a;
       +}
       +int
       +nfs3treadpack(uchar *a, uchar *ea, uchar **pa, Nfs3TRead *x)
       +{
       +        if(nfs3handlepack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(sunuint64pack(a, ea, &a, &x->offset) < 0) goto Err;
       +        if(sunuint32pack(a, ea, &a, &x->count) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3treadunpack(uchar *a, uchar *ea, uchar **pa, Nfs3TRead *x)
       +{
       +        if(nfs3handleunpack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(sunuint64unpack(a, ea, &a, &x->offset) < 0) goto Err;
       +        if(sunuint32unpack(a, ea, &a, &x->count) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3rreadprint(Fmt *fmt, Nfs3RRead *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3RRead");
       +        fmtprint(fmt, "\t%s=", "status");
       +        fmtprint(fmt, "%s", nfs3statusstr(x->status));
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "haveAttr");
       +        fmtprint(fmt, "%d", x->haveAttr);
       +        fmtprint(fmt, "\n");
       +        switch(x->haveAttr){
       +        case 1:
       +                fmtprint(fmt, "\t%s=", "attr");
       +                nfs3attrprint(fmt, &x->attr);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                fmtprint(fmt, "\t%s=", "count");
       +                fmtprint(fmt, "%ud", x->count);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "eof");
       +                fmtprint(fmt, "%d", x->eof);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "data");
       +                if(x->ndata <= 32)
       +                        fmtprint(fmt, "%.*H", x->ndata, x->data);
       +                else
       +                        fmtprint(fmt, "%.32H...", x->data);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +}
       +uint
       +nfs3rreadsize(Nfs3RRead *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4 + 4;
       +        switch(x->haveAttr){
       +        case 1:
       +                a = a + nfs3attrsize(&x->attr);
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                a = a + 4 + 4 + sunvaropaquesize(x->ndata);
       +                break;
       +        }
       +        return a;
       +}
       +int
       +nfs3rreadpack(uchar *a, uchar *ea, uchar **pa, Nfs3RRead *x)
       +{
       +        int i;
       +
       +        if(i=x->status, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        if(sunuint1pack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +        switch(x->haveAttr){
       +        case 1:
       +                if(nfs3attrpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(sunuint32pack(a, ea, &a, &x->count) < 0) goto Err;
       +                if(sunuint1pack(a, ea, &a, &x->eof) < 0) goto Err;
       +                if(sunvaropaquepack(a, ea, &a, &x->data, &x->ndata, x->count) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3rreadunpack(uchar *a, uchar *ea, uchar **pa, Nfs3RRead *x)
       +{
       +        int i;
       +
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->status = i;
       +        if(sunuint1unpack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +        switch(x->haveAttr){
       +        case 1:
       +                if(nfs3attrunpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(sunuint32unpack(a, ea, &a, &x->count) < 0) goto Err;
       +                if(sunuint1unpack(a, ea, &a, &x->eof) < 0) goto Err;
       +                if(sunvaropaqueunpack(a, ea, &a, &x->data, &x->ndata, x->count) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +char*
       +nfs3syncstr(Nfs3Sync x)
       +{
       +        switch(x){
       +        case Nfs3SyncNone:
       +                return "Nfs3SyncNone";
       +        case Nfs3SyncData:
       +                return "Nfs3SyncData";
       +        case Nfs3SyncFile:
       +                return "Nfs3SyncFile";
       +        default:
       +                return "unknown";
       +        }
       +}
       +
       +void
       +nfs3twriteprint(Fmt *fmt, Nfs3TWrite *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3TWrite");
       +        fmtprint(fmt, "\t%s=", "file");
       +        nfs3handleprint(fmt, &x->handle);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "offset");
       +        fmtprint(fmt, "%llud", x->offset);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "count");
       +        fmtprint(fmt, "%ud", x->count);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "stable");
       +        fmtprint(fmt, "%s", nfs3syncstr(x->stable));
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "data");
       +        if(x->ndata > 32)
       +                fmtprint(fmt, "%.32H... (%d)", x->data, x->ndata);
       +        else
       +                fmtprint(fmt, "%.*H", x->ndata, x->data);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3twritesize(Nfs3TWrite *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + nfs3handlesize(&x->handle) + 8 + 4 + 4 + sunvaropaquesize(x->ndata);
       +        return a;
       +}
       +int
       +nfs3twritepack(uchar *a, uchar *ea, uchar **pa, Nfs3TWrite *x)
       +{
       +        int i;
       +
       +        if(nfs3handlepack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(sunuint64pack(a, ea, &a, &x->offset) < 0) goto Err;
       +        if(sunuint32pack(a, ea, &a, &x->count) < 0) goto Err;
       +        if(i=x->stable, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        if(sunvaropaquepack(a, ea, &a, &x->data, &x->ndata, x->count) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3twriteunpack(uchar *a, uchar *ea, uchar **pa, Nfs3TWrite *x)
       +{
       +        int i;
       +
       +        if(nfs3handleunpack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(sunuint64unpack(a, ea, &a, &x->offset) < 0) goto Err;
       +        if(sunuint32unpack(a, ea, &a, &x->count) < 0) goto Err;
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->stable = i;
       +        if(sunvaropaqueunpack(a, ea, &a, &x->data, &x->ndata, x->count) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3rwriteprint(Fmt *fmt, Nfs3RWrite *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3RWrite");
       +        fmtprint(fmt, "\t%s=", "status");
       +        fmtprint(fmt, "%s", nfs3statusstr(x->status));
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "wcc");
       +        nfs3wccprint(fmt, &x->wcc);
       +        fmtprint(fmt, "\n");
       +        switch(x->status){
       +        case Nfs3Ok:
       +                fmtprint(fmt, "\t%s=", "count");
       +                fmtprint(fmt, "%ud", x->count);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "committed");
       +                fmtprint(fmt, "%s", nfs3syncstr(x->committed));
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "verf");
       +                fmtprint(fmt, "%.*H", Nfs3WriteVerfSize, x->verf);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +}
       +uint
       +nfs3rwritesize(Nfs3RWrite *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4 + nfs3wccsize(&x->wcc);
       +        switch(x->status){
       +        case Nfs3Ok:
       +                a = a + 4 + 4 + Nfs3WriteVerfSize;
       +                break;
       +        }
       +        return a;
       +}
       +int
       +nfs3rwritepack(uchar *a, uchar *ea, uchar **pa, Nfs3RWrite *x)
       +{
       +        int i;
       +
       +        if(i=x->status, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        if(nfs3wccpack(a, ea, &a, &x->wcc) < 0) goto Err;
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(sunuint32pack(a, ea, &a, &x->count) < 0) goto Err;
       +                if(i=x->committed, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +                if(sunfixedopaquepack(a, ea, &a, x->verf, Nfs3WriteVerfSize) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3rwriteunpack(uchar *a, uchar *ea, uchar **pa, Nfs3RWrite *x)
       +{
       +        int i;
       +
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->status = i;
       +        if(nfs3wccunpack(a, ea, &a, &x->wcc) < 0) goto Err;
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(sunuint32unpack(a, ea, &a, &x->count) < 0) goto Err;
       +                if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->committed = i;
       +                if(sunfixedopaqueunpack(a, ea, &a, x->verf, Nfs3WriteVerfSize) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +char*
       +nfs3createstr(Nfs3Create x)
       +{
       +        switch(x){
       +        case Nfs3CreateUnchecked:
       +                return "Nfs3CreateUnchecked";
       +        case Nfs3CreateGuarded:
       +                return "Nfs3CreateGuarded";
       +        case Nfs3CreateExclusive:
       +                return "Nfs3CreateExclusive";
       +        default:
       +                return "unknown";
       +        }
       +}
       +
       +void
       +nfs3tcreateprint(Fmt *fmt, Nfs3TCreate *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3TCreate");
       +        fmtprint(fmt, "\t%s=", "handle");
       +        nfs3handleprint(fmt, &x->handle);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "name");
       +        fmtprint(fmt, "\"%s\"", x->name);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "mode");
       +        fmtprint(fmt, "%s", nfs3createstr(x->mode));
       +        fmtprint(fmt, "\n");
       +        switch(x->mode){
       +        case Nfs3CreateUnchecked:
       +        case Nfs3CreateGuarded:
       +                fmtprint(fmt, "\t%s=", "attr");
       +                nfs3setattrprint(fmt, &x->attr);
       +                fmtprint(fmt, "\n");
       +                break;
       +        case Nfs3CreateExclusive:
       +                fmtprint(fmt, "\t%s=", "verf");
       +                fmtprint(fmt, "%.*H", Nfs3CreateVerfSize, x->verf);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +}
       +uint
       +nfs3tcreatesize(Nfs3TCreate *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + nfs3handlesize(&x->handle) + sunstringsize(x->name) + 4;
       +        switch(x->mode){
       +        case Nfs3CreateUnchecked:
       +        case Nfs3CreateGuarded:
       +                a = a + nfs3setattrsize(&x->attr);
       +                break;
       +        case Nfs3CreateExclusive:
       +                a = a + Nfs3CreateVerfSize;
       +                break;
       +        }
       +        return a;
       +}
       +int
       +nfs3tcreatepack(uchar *a, uchar *ea, uchar **pa, Nfs3TCreate *x)
       +{
       +        int i;
       +
       +        if(nfs3handlepack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(sunstringpack(a, ea, &a, &x->name, -1) < 0) goto Err;
       +        if(i=x->mode, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        switch(x->mode){
       +        case Nfs3CreateUnchecked:
       +        case Nfs3CreateGuarded:
       +                if(nfs3setattrpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        case Nfs3CreateExclusive:
       +                if(sunfixedopaquepack(a, ea, &a, x->verf, Nfs3CreateVerfSize) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3tcreateunpack(uchar *a, uchar *ea, uchar **pa, Nfs3TCreate *x)
       +{
       +        int i;
       +
       +        if(nfs3handleunpack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(sunstringunpack(a, ea, &a, &x->name, -1) < 0) goto Err;
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->mode = i;
       +        switch(x->mode){
       +        case Nfs3CreateUnchecked:
       +        case Nfs3CreateGuarded:
       +                if(nfs3setattrunpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        case Nfs3CreateExclusive:
       +                if(sunfixedopaqueunpack(a, ea, &a, x->verf, Nfs3CreateVerfSize) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3rcreateprint(Fmt *fmt, Nfs3RCreate *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3RCreate");
       +        fmtprint(fmt, "\t%s=", "status");
       +        fmtprint(fmt, "%s", nfs3statusstr(x->status));
       +        fmtprint(fmt, "\n");
       +        switch(x->status){
       +        case Nfs3Ok:
       +                fmtprint(fmt, "\t%s=", "haveHandle");
       +                fmtprint(fmt, "%d", x->haveHandle);
       +                fmtprint(fmt, "\n");
       +                switch(x->haveHandle){
       +                case 1:
       +                        fmtprint(fmt, "\t%s=", "handle");
       +                        nfs3handleprint(fmt, &x->handle);
       +                        fmtprint(fmt, "\n");
       +                        break;
       +                }
       +                fmtprint(fmt, "\t%s=", "haveAttr");
       +                fmtprint(fmt, "%d", x->haveAttr);
       +                fmtprint(fmt, "\n");
       +                switch(x->haveAttr){
       +                case 1:
       +                        fmtprint(fmt, "\t%s=", "attr");
       +                        nfs3attrprint(fmt, &x->attr);
       +                        fmtprint(fmt, "\n");
       +                        break;
       +                }
       +                break;
       +        }
       +        fmtprint(fmt, "\t%s=", "dirWcc");
       +        nfs3wccprint(fmt, &x->dirWcc);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3rcreatesize(Nfs3RCreate *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4;
       +        switch(x->status){
       +        case Nfs3Ok:
       +                a = a + 4;
       +                switch(x->haveHandle){
       +                case 1:
       +                        a = a + nfs3handlesize(&x->handle);
       +                        break;
       +                }
       +                a = a + 4;
       +                switch(x->haveAttr){
       +                case 1:
       +                        a = a + nfs3attrsize(&x->attr);
       +                        break;
       +                }
       +                        break;
       +        }
       +        a = a + nfs3wccsize(&x->dirWcc);
       +        return a;
       +}
       +int
       +nfs3rcreatepack(uchar *a, uchar *ea, uchar **pa, Nfs3RCreate *x)
       +{
       +        int i;
       +
       +        if(i=x->status, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(sunuint1pack(a, ea, &a, &x->haveHandle) < 0) goto Err;
       +                switch(x->haveHandle){
       +                case 1:
       +                        if(nfs3handlepack(a, ea, &a, &x->handle) < 0) goto Err;
       +                        break;
       +                }
       +                if(sunuint1pack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +                switch(x->haveAttr){
       +                case 1:
       +                        if(nfs3attrpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                        break;
       +                }
       +                break;
       +        }
       +        if(nfs3wccpack(a, ea, &a, &x->dirWcc) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3rcreateunpack(uchar *a, uchar *ea, uchar **pa, Nfs3RCreate *x)
       +{
       +        int i;
       +
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->status = i;
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(sunuint1unpack(a, ea, &a, &x->haveHandle) < 0) goto Err;
       +                switch(x->haveHandle){
       +                case 1:
       +                        if(nfs3handleunpack(a, ea, &a, &x->handle) < 0) goto Err;
       +                        break;
       +                }
       +                if(sunuint1unpack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +                switch(x->haveAttr){
       +                case 1:
       +                        if(nfs3attrunpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                        break;
       +                }
       +                break;
       +        }
       +        if(nfs3wccunpack(a, ea, &a, &x->dirWcc) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3tmkdirprint(Fmt *fmt, Nfs3TMkdir *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3TMkdir");
       +        fmtprint(fmt, "\t%s=", "handle");
       +        nfs3handleprint(fmt, &x->handle);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "name");
       +        fmtprint(fmt, "\"%s\"", x->name);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "attr");
       +        nfs3setattrprint(fmt, &x->attr);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3tmkdirsize(Nfs3TMkdir *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + nfs3handlesize(&x->handle) + sunstringsize(x->name) + nfs3setattrsize(&x->attr);
       +        return a;
       +}
       +int
       +nfs3tmkdirpack(uchar *a, uchar *ea, uchar **pa, Nfs3TMkdir *x)
       +{
       +        if(nfs3handlepack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(sunstringpack(a, ea, &a, &x->name, -1) < 0) goto Err;
       +        if(nfs3setattrpack(a, ea, &a, &x->attr) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3tmkdirunpack(uchar *a, uchar *ea, uchar **pa, Nfs3TMkdir *x)
       +{
       +        if(nfs3handleunpack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(sunstringunpack(a, ea, &a, &x->name, -1) < 0) goto Err;
       +        if(nfs3setattrunpack(a, ea, &a, &x->attr) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3rmkdirprint(Fmt *fmt, Nfs3RMkdir *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3RMkdir");
       +        fmtprint(fmt, "\t%s=", "status");
       +        fmtprint(fmt, "%s", nfs3statusstr(x->status));
       +        fmtprint(fmt, "\n");
       +        switch(x->status){
       +        case Nfs3Ok:
       +                fmtprint(fmt, "\t%s=", "haveHandle");
       +                fmtprint(fmt, "%d", x->haveHandle);
       +                fmtprint(fmt, "\n");
       +                switch(x->haveHandle){
       +                case 1:
       +                        fmtprint(fmt, "\t%s=", "handle");
       +                        nfs3handleprint(fmt, &x->handle);
       +                        fmtprint(fmt, "\n");
       +                        break;
       +                }
       +                fmtprint(fmt, "\t%s=", "haveAttr");
       +                fmtprint(fmt, "%d", x->haveAttr);
       +                fmtprint(fmt, "\n");
       +                switch(x->haveAttr){
       +                case 1:
       +                        fmtprint(fmt, "\t%s=", "attr");
       +                        nfs3attrprint(fmt, &x->attr);
       +                        fmtprint(fmt, "\n");
       +                        break;
       +                }
       +                break;
       +        }
       +        fmtprint(fmt, "\t%s=", "dirWcc");
       +        nfs3wccprint(fmt, &x->dirWcc);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3rmkdirsize(Nfs3RMkdir *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4;
       +        switch(x->status){
       +        case Nfs3Ok:
       +                a = a + 4;
       +                switch(x->haveHandle){
       +                case 1:
       +                        a = a + nfs3handlesize(&x->handle);
       +                        break;
       +                }
       +                a = a + 4;
       +                switch(x->haveAttr){
       +                case 1:
       +                        a = a + nfs3attrsize(&x->attr);
       +                        break;
       +                }
       +                        break;
       +        }
       +        a = a + nfs3wccsize(&x->dirWcc);
       +        return a;
       +}
       +int
       +nfs3rmkdirpack(uchar *a, uchar *ea, uchar **pa, Nfs3RMkdir *x)
       +{
       +        int i;
       +
       +        if(i=x->status, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(sunuint1pack(a, ea, &a, &x->haveHandle) < 0) goto Err;
       +                switch(x->haveHandle){
       +                case 1:
       +                        if(nfs3handlepack(a, ea, &a, &x->handle) < 0) goto Err;
       +                        break;
       +                }
       +                if(sunuint1pack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +                switch(x->haveAttr){
       +                case 1:
       +                        if(nfs3attrpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                        break;
       +                }
       +                break;
       +        }
       +        if(nfs3wccpack(a, ea, &a, &x->dirWcc) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3rmkdirunpack(uchar *a, uchar *ea, uchar **pa, Nfs3RMkdir *x)
       +{
       +        int i;
       +
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->status = i;
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(sunuint1unpack(a, ea, &a, &x->haveHandle) < 0) goto Err;
       +                switch(x->haveHandle){
       +                case 1:
       +                        if(nfs3handleunpack(a, ea, &a, &x->handle) < 0) goto Err;
       +                        break;
       +                }
       +                if(sunuint1unpack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +                switch(x->haveAttr){
       +                case 1:
       +                        if(nfs3attrunpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                        break;
       +                }
       +                break;
       +        }
       +        if(nfs3wccunpack(a, ea, &a, &x->dirWcc) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3tsymlinkprint(Fmt *fmt, Nfs3TSymlink *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3TSymlink");
       +        fmtprint(fmt, "\t%s=", "handle");
       +        nfs3handleprint(fmt, &x->handle);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "name");
       +        fmtprint(fmt, "\"%s\"", x->name);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "attr");
       +        nfs3setattrprint(fmt, &x->attr);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "data");
       +        fmtprint(fmt, "\"%s\"", x->data);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3tsymlinksize(Nfs3TSymlink *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + nfs3handlesize(&x->handle) + sunstringsize(x->name) + nfs3setattrsize(&x->attr) + sunstringsize(x->data);
       +        return a;
       +}
       +int
       +nfs3tsymlinkpack(uchar *a, uchar *ea, uchar **pa, Nfs3TSymlink *x)
       +{
       +        if(nfs3handlepack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(sunstringpack(a, ea, &a, &x->name, -1) < 0) goto Err;
       +        if(nfs3setattrpack(a, ea, &a, &x->attr) < 0) goto Err;
       +        if(sunstringpack(a, ea, &a, &x->data, -1) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3tsymlinkunpack(uchar *a, uchar *ea, uchar **pa, Nfs3TSymlink *x)
       +{
       +        if(nfs3handleunpack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(sunstringunpack(a, ea, &a, &x->name, -1) < 0) goto Err;
       +        if(nfs3setattrunpack(a, ea, &a, &x->attr) < 0) goto Err;
       +        if(sunstringunpack(a, ea, &a, &x->data, -1) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3rsymlinkprint(Fmt *fmt, Nfs3RSymlink *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3RSymlink");
       +        fmtprint(fmt, "\t%s=", "status");
       +        fmtprint(fmt, "%s", nfs3statusstr(x->status));
       +        fmtprint(fmt, "\n");
       +        switch(x->status){
       +        case Nfs3Ok:
       +                fmtprint(fmt, "\t%s=", "haveHandle");
       +                fmtprint(fmt, "%d", x->haveHandle);
       +                fmtprint(fmt, "\n");
       +                switch(x->haveHandle){
       +                case 1:
       +                        fmtprint(fmt, "\t%s=", "handle");
       +                        nfs3handleprint(fmt, &x->handle);
       +                        fmtprint(fmt, "\n");
       +                        break;
       +                }
       +                fmtprint(fmt, "\t%s=", "haveAttr");
       +                fmtprint(fmt, "%d", x->haveAttr);
       +                fmtprint(fmt, "\n");
       +                switch(x->haveAttr){
       +                case 1:
       +                        fmtprint(fmt, "\t%s=", "attr");
       +                        nfs3attrprint(fmt, &x->attr);
       +                        fmtprint(fmt, "\n");
       +                        break;
       +                }
       +                break;
       +        }
       +        fmtprint(fmt, "\t%s=", "dirWcc");
       +        nfs3wccprint(fmt, &x->dirWcc);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3rsymlinksize(Nfs3RSymlink *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4;
       +        switch(x->status){
       +        case Nfs3Ok:
       +                a = a + 4;
       +                switch(x->haveHandle){
       +                case 1:
       +                        a = a + nfs3handlesize(&x->handle);
       +                        break;
       +                }
       +                a = a + 4;
       +                switch(x->haveAttr){
       +                case 1:
       +                        a = a + nfs3attrsize(&x->attr);
       +                        break;
       +                }
       +                        break;
       +        }
       +        a = a + nfs3wccsize(&x->dirWcc);
       +        return a;
       +}
       +int
       +nfs3rsymlinkpack(uchar *a, uchar *ea, uchar **pa, Nfs3RSymlink *x)
       +{
       +        int i;
       +
       +        if(i=x->status, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(sunuint1pack(a, ea, &a, &x->haveHandle) < 0) goto Err;
       +                switch(x->haveHandle){
       +                case 1:
       +                        if(nfs3handlepack(a, ea, &a, &x->handle) < 0) goto Err;
       +                        break;
       +                }
       +                if(sunuint1pack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +                switch(x->haveAttr){
       +                case 1:
       +                        if(nfs3attrpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                        break;
       +                }
       +                break;
       +        }
       +        if(nfs3wccpack(a, ea, &a, &x->dirWcc) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3rsymlinkunpack(uchar *a, uchar *ea, uchar **pa, Nfs3RSymlink *x)
       +{
       +        int i;
       +
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->status = i;
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(sunuint1unpack(a, ea, &a, &x->haveHandle) < 0) goto Err;
       +                switch(x->haveHandle){
       +                case 1:
       +                        if(nfs3handleunpack(a, ea, &a, &x->handle) < 0) goto Err;
       +                        break;
       +                }
       +                if(sunuint1unpack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +                switch(x->haveAttr){
       +                case 1:
       +                        if(nfs3attrunpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                        break;
       +                }
       +                break;
       +        }
       +        if(nfs3wccunpack(a, ea, &a, &x->dirWcc) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3tmknodprint(Fmt *fmt, Nfs3TMknod *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3TMknod");
       +        fmtprint(fmt, "\t%s=", "handle");
       +        nfs3handleprint(fmt, &x->handle);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "name");
       +        fmtprint(fmt, "\"%s\"", x->name);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "type");
       +        fmtprint(fmt, "%s", nfs3filetypestr(x->type));
       +        fmtprint(fmt, "\n");
       +        switch(x->type){
       +        case Nfs3FileChar:
       +        case Nfs3FileBlock:
       +                fmtprint(fmt, "\t%s=", "attr");
       +                nfs3setattrprint(fmt, &x->attr);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "major");
       +                fmtprint(fmt, "%ud", x->major);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "minor");
       +                fmtprint(fmt, "%ud", x->minor);
       +                fmtprint(fmt, "\n");
       +                break;
       +        case Nfs3FileSocket:
       +        case Nfs3FileFifo:
       +                fmtprint(fmt, "\t%s=", "attr");
       +                nfs3setattrprint(fmt, &x->attr);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +}
       +uint
       +nfs3tmknodsize(Nfs3TMknod *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + nfs3handlesize(&x->handle) + sunstringsize(x->name) + 4;
       +        switch(x->type){
       +        case Nfs3FileChar:
       +        case Nfs3FileBlock:
       +                a = a + nfs3setattrsize(&x->attr) + 4 + 4;
       +                break;
       +        case Nfs3FileSocket:
       +        case Nfs3FileFifo:
       +                a = a + nfs3setattrsize(&x->attr);
       +                break;
       +        }
       +        return a;
       +}
       +int
       +nfs3tmknodpack(uchar *a, uchar *ea, uchar **pa, Nfs3TMknod *x)
       +{
       +        int i;
       +
       +        if(nfs3handlepack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(sunstringpack(a, ea, &a, &x->name, -1) < 0) goto Err;
       +        if(i=x->type, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        switch(x->type){
       +        case Nfs3FileChar:
       +        case Nfs3FileBlock:
       +                if(nfs3setattrpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                if(sunuint32pack(a, ea, &a, &x->major) < 0) goto Err;
       +                if(sunuint32pack(a, ea, &a, &x->minor) < 0) goto Err;
       +                break;
       +        case Nfs3FileSocket:
       +        case Nfs3FileFifo:
       +                if(nfs3setattrpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3tmknodunpack(uchar *a, uchar *ea, uchar **pa, Nfs3TMknod *x)
       +{
       +        int i;
       +
       +        if(nfs3handleunpack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(sunstringunpack(a, ea, &a, &x->name, -1) < 0) goto Err;
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->type = i;
       +        switch(x->type){
       +        case Nfs3FileChar:
       +        case Nfs3FileBlock:
       +                if(nfs3setattrunpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                if(sunuint32unpack(a, ea, &a, &x->major) < 0) goto Err;
       +                if(sunuint32unpack(a, ea, &a, &x->minor) < 0) goto Err;
       +                break;
       +        case Nfs3FileSocket:
       +        case Nfs3FileFifo:
       +                if(nfs3setattrunpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3rmknodprint(Fmt *fmt, Nfs3RMknod *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3RMknod");
       +        fmtprint(fmt, "\t%s=", "status");
       +        fmtprint(fmt, "%s", nfs3statusstr(x->status));
       +        fmtprint(fmt, "\n");
       +        switch(x->status){
       +        case Nfs3Ok:
       +                fmtprint(fmt, "\t%s=", "haveHandle");
       +                fmtprint(fmt, "%d", x->haveHandle);
       +                fmtprint(fmt, "\n");
       +                switch(x->haveHandle){
       +                case 1:
       +                        fmtprint(fmt, "\t%s=", "handle");
       +                        nfs3handleprint(fmt, &x->handle);
       +                        fmtprint(fmt, "\n");
       +                        break;
       +                }
       +                fmtprint(fmt, "\t%s=", "haveAttr");
       +                fmtprint(fmt, "%d", x->haveAttr);
       +                fmtprint(fmt, "\n");
       +                switch(x->haveAttr){
       +                case 1:
       +                        fmtprint(fmt, "\t%s=", "attr");
       +                        nfs3attrprint(fmt, &x->attr);
       +                        fmtprint(fmt, "\n");
       +                        break;
       +                }
       +                break;
       +        }
       +        fmtprint(fmt, "\t%s=", "dirWcc");
       +        nfs3wccprint(fmt, &x->dirWcc);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3rmknodsize(Nfs3RMknod *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4;
       +        switch(x->status){
       +        case Nfs3Ok:
       +                a = a + 4;
       +                switch(x->haveHandle){
       +                case 1:
       +                        a = a + nfs3handlesize(&x->handle);
       +                        break;
       +                }
       +                a = a + 4;
       +                switch(x->haveAttr){
       +                case 1:
       +                        a = a + nfs3attrsize(&x->attr);
       +                        break;
       +                }
       +                        break;
       +        }
       +        a = a + nfs3wccsize(&x->dirWcc);
       +        return a;
       +}
       +int
       +nfs3rmknodpack(uchar *a, uchar *ea, uchar **pa, Nfs3RMknod *x)
       +{
       +        int i;
       +
       +        if(i=x->status, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(sunuint1pack(a, ea, &a, &x->haveHandle) < 0) goto Err;
       +                switch(x->haveHandle){
       +                case 1:
       +                        if(nfs3handlepack(a, ea, &a, &x->handle) < 0) goto Err;
       +                        break;
       +                }
       +                if(sunuint1pack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +                switch(x->haveAttr){
       +                case 1:
       +                        if(nfs3attrpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                        break;
       +                }
       +                break;
       +        }
       +        if(nfs3wccpack(a, ea, &a, &x->dirWcc) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3rmknodunpack(uchar *a, uchar *ea, uchar **pa, Nfs3RMknod *x)
       +{
       +        int i;
       +
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->status = i;
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(sunuint1unpack(a, ea, &a, &x->haveHandle) < 0) goto Err;
       +                switch(x->haveHandle){
       +                case 1:
       +                        if(nfs3handleunpack(a, ea, &a, &x->handle) < 0) goto Err;
       +                        break;
       +                }
       +                if(sunuint1unpack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +                switch(x->haveAttr){
       +                case 1:
       +                        if(nfs3attrunpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                        break;
       +                }
       +                break;
       +        }
       +        if(nfs3wccunpack(a, ea, &a, &x->dirWcc) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3tremoveprint(Fmt *fmt, Nfs3TRemove *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3TRemove");
       +        fmtprint(fmt, "\t%s=", "handle");
       +        nfs3handleprint(fmt, &x->handle);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "name");
       +        fmtprint(fmt, "\"%s\"", x->name);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3tremovesize(Nfs3TRemove *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + nfs3handlesize(&x->handle) + sunstringsize(x->name);
       +        return a;
       +}
       +int
       +nfs3tremovepack(uchar *a, uchar *ea, uchar **pa, Nfs3TRemove *x)
       +{
       +        if(nfs3handlepack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(sunstringpack(a, ea, &a, &x->name, -1) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3tremoveunpack(uchar *a, uchar *ea, uchar **pa, Nfs3TRemove *x)
       +{
       +        if(nfs3handleunpack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(sunstringunpack(a, ea, &a, &x->name, -1) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3rremoveprint(Fmt *fmt, Nfs3RRemove *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3RRemove");
       +        fmtprint(fmt, "\t%s=", "status");
       +        fmtprint(fmt, "%s", nfs3statusstr(x->status));
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "wcc");
       +        nfs3wccprint(fmt, &x->wcc);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3rremovesize(Nfs3RRemove *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4 + nfs3wccsize(&x->wcc);
       +        return a;
       +}
       +int
       +nfs3rremovepack(uchar *a, uchar *ea, uchar **pa, Nfs3RRemove *x)
       +{
       +        int i;
       +
       +        if(i=x->status, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        if(nfs3wccpack(a, ea, &a, &x->wcc) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3rremoveunpack(uchar *a, uchar *ea, uchar **pa, Nfs3RRemove *x)
       +{
       +        int i;
       +
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->status = i;
       +        if(nfs3wccunpack(a, ea, &a, &x->wcc) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3trmdirprint(Fmt *fmt, Nfs3TRmdir *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3TRmdir");
       +        fmtprint(fmt, "\t%s=", "handle");
       +        nfs3handleprint(fmt, &x->handle);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "name");
       +        fmtprint(fmt, "\"%s\"", x->name);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3trmdirsize(Nfs3TRmdir *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + nfs3handlesize(&x->handle) + sunstringsize(x->name);
       +        return a;
       +}
       +int
       +nfs3trmdirpack(uchar *a, uchar *ea, uchar **pa, Nfs3TRmdir *x)
       +{
       +        if(nfs3handlepack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(sunstringpack(a, ea, &a, &x->name, -1) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3trmdirunpack(uchar *a, uchar *ea, uchar **pa, Nfs3TRmdir *x)
       +{
       +        if(nfs3handleunpack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(sunstringunpack(a, ea, &a, &x->name, -1) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3rrmdirprint(Fmt *fmt, Nfs3RRmdir *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3RRmdir");
       +        fmtprint(fmt, "\t%s=", "status");
       +        fmtprint(fmt, "%s", nfs3statusstr(x->status));
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "wcc");
       +        nfs3wccprint(fmt, &x->wcc);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3rrmdirsize(Nfs3RRmdir *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4 + nfs3wccsize(&x->wcc);
       +        return a;
       +}
       +int
       +nfs3rrmdirpack(uchar *a, uchar *ea, uchar **pa, Nfs3RRmdir *x)
       +{
       +        int i;
       +
       +        if(i=x->status, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        if(nfs3wccpack(a, ea, &a, &x->wcc) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3rrmdirunpack(uchar *a, uchar *ea, uchar **pa, Nfs3RRmdir *x)
       +{
       +        int i;
       +
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->status = i;
       +        if(nfs3wccunpack(a, ea, &a, &x->wcc) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3trenameprint(Fmt *fmt, Nfs3TRename *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3TRename");
       +        fmtprint(fmt, "\t%s=", "from");
       +        fmtprint(fmt, "{\n");
       +        fmtprint(fmt, "\t\t%s=", "handle");
       +        nfs3handleprint(fmt, &x->from.handle);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t\t%s=", "name");
       +        fmtprint(fmt, "\"%s\"", x->from.name);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t}");
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "to");
       +        fmtprint(fmt, "{\n");
       +        fmtprint(fmt, "\t\t%s=", "handle");
       +        nfs3handleprint(fmt, &x->to.handle);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t\t%s=", "name");
       +        fmtprint(fmt, "\"%s\"", x->to.name);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t}");
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3trenamesize(Nfs3TRename *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + nfs3handlesize(&x->from.handle) + sunstringsize(x->from.name) + nfs3handlesize(&x->to.handle) + sunstringsize(x->to.name);
       +        return a;
       +}
       +int
       +nfs3trenamepack(uchar *a, uchar *ea, uchar **pa, Nfs3TRename *x)
       +{
       +        if(nfs3handlepack(a, ea, &a, &x->from.handle) < 0) goto Err;
       +        if(sunstringpack(a, ea, &a, &x->from.name, -1) < 0) goto Err;
       +        if(nfs3handlepack(a, ea, &a, &x->to.handle) < 0) goto Err;
       +        if(sunstringpack(a, ea, &a, &x->to.name, -1) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3trenameunpack(uchar *a, uchar *ea, uchar **pa, Nfs3TRename *x)
       +{
       +        if(nfs3handleunpack(a, ea, &a, &x->from.handle) < 0) goto Err;
       +        if(sunstringunpack(a, ea, &a, &x->from.name, -1) < 0) goto Err;
       +        if(nfs3handleunpack(a, ea, &a, &x->to.handle) < 0) goto Err;
       +        if(sunstringunpack(a, ea, &a, &x->to.name, -1) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3rrenameprint(Fmt *fmt, Nfs3RRename *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3RRename");
       +        fmtprint(fmt, "\t%s=", "status");
       +        fmtprint(fmt, "%s", nfs3statusstr(x->status));
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "fromWcc");
       +        nfs3wccprint(fmt, &x->fromWcc);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "toWcc");
       +        nfs3wccprint(fmt, &x->toWcc);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3rrenamesize(Nfs3RRename *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4 + nfs3wccsize(&x->fromWcc) + nfs3wccsize(&x->toWcc);
       +        return a;
       +}
       +int
       +nfs3rrenamepack(uchar *a, uchar *ea, uchar **pa, Nfs3RRename *x)
       +{
       +        int i;
       +
       +        if(i=x->status, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        if(nfs3wccpack(a, ea, &a, &x->fromWcc) < 0) goto Err;
       +        if(nfs3wccpack(a, ea, &a, &x->toWcc) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3rrenameunpack(uchar *a, uchar *ea, uchar **pa, Nfs3RRename *x)
       +{
       +        int i;
       +
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->status = i;
       +        if(nfs3wccunpack(a, ea, &a, &x->fromWcc) < 0) goto Err;
       +        if(nfs3wccunpack(a, ea, &a, &x->toWcc) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3tlinkprint(Fmt *fmt, Nfs3TLink *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3TLink");
       +        fmtprint(fmt, "\t%s=", "handle");
       +        nfs3handleprint(fmt, &x->handle);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "link");
       +        fmtprint(fmt, "{\n");
       +        fmtprint(fmt, "\t\t%s=", "handle");
       +        nfs3handleprint(fmt, &x->link.handle);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t\t%s=", "name");
       +        fmtprint(fmt, "\"%s\"", x->link.name);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t}");
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3tlinksize(Nfs3TLink *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + nfs3handlesize(&x->handle) + nfs3handlesize(&x->link.handle) + sunstringsize(x->link.name);
       +        return a;
       +}
       +int
       +nfs3tlinkpack(uchar *a, uchar *ea, uchar **pa, Nfs3TLink *x)
       +{
       +        if(nfs3handlepack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(nfs3handlepack(a, ea, &a, &x->link.handle) < 0) goto Err;
       +        if(sunstringpack(a, ea, &a, &x->link.name, -1) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3tlinkunpack(uchar *a, uchar *ea, uchar **pa, Nfs3TLink *x)
       +{
       +        if(nfs3handleunpack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(nfs3handleunpack(a, ea, &a, &x->link.handle) < 0) goto Err;
       +        if(sunstringunpack(a, ea, &a, &x->link.name, -1) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3rlinkprint(Fmt *fmt, Nfs3RLink *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3RLink");
       +        fmtprint(fmt, "\t%s=", "status");
       +        fmtprint(fmt, "%s", nfs3statusstr(x->status));
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "haveAttr");
       +        fmtprint(fmt, "%d", x->haveAttr);
       +        fmtprint(fmt, "\n");
       +        switch(x->haveAttr){
       +        case 1:
       +                fmtprint(fmt, "\t%s=", "attr");
       +                nfs3attrprint(fmt, &x->attr);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +        fmtprint(fmt, "\t%s=", "dirWcc");
       +        nfs3wccprint(fmt, &x->dirWcc);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3rlinksize(Nfs3RLink *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4 + 4;
       +        switch(x->haveAttr){
       +        case 1:
       +                a = a + nfs3attrsize(&x->attr);
       +                break;
       +        }
       +        a = a + nfs3wccsize(&x->dirWcc);
       +        return a;
       +}
       +int
       +nfs3rlinkpack(uchar *a, uchar *ea, uchar **pa, Nfs3RLink *x)
       +{
       +        int i;
       +
       +        if(i=x->status, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        if(sunuint1pack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +        switch(x->haveAttr){
       +        case 1:
       +                if(nfs3attrpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        }
       +        if(nfs3wccpack(a, ea, &a, &x->dirWcc) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3rlinkunpack(uchar *a, uchar *ea, uchar **pa, Nfs3RLink *x)
       +{
       +        int i;
       +
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->status = i;
       +        if(sunuint1unpack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +        switch(x->haveAttr){
       +        case 1:
       +                if(nfs3attrunpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        }
       +        if(nfs3wccunpack(a, ea, &a, &x->dirWcc) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3treaddirprint(Fmt *fmt, Nfs3TReadDir *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3TReadDir");
       +        fmtprint(fmt, "\t%s=", "handle");
       +        nfs3handleprint(fmt, &x->handle);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "cookie");
       +        fmtprint(fmt, "%llud", x->cookie);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "verf");
       +        fmtprint(fmt, "%.*H", Nfs3CookieVerfSize, x->verf);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "count");
       +        fmtprint(fmt, "%ud", x->count);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3treaddirsize(Nfs3TReadDir *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + nfs3handlesize(&x->handle) + 8 + Nfs3CookieVerfSize + 4;
       +        return a;
       +}
       +int
       +nfs3treaddirpack(uchar *a, uchar *ea, uchar **pa, Nfs3TReadDir *x)
       +{
       +        if(nfs3handlepack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(sunuint64pack(a, ea, &a, &x->cookie) < 0) goto Err;
       +        if(sunfixedopaquepack(a, ea, &a, x->verf, Nfs3CookieVerfSize) < 0) goto Err;
       +        if(sunuint32pack(a, ea, &a, &x->count) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3treaddirunpack(uchar *a, uchar *ea, uchar **pa, Nfs3TReadDir *x)
       +{
       +        if(nfs3handleunpack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(sunuint64unpack(a, ea, &a, &x->cookie) < 0) goto Err;
       +        if(sunfixedopaqueunpack(a, ea, &a, x->verf, Nfs3CookieVerfSize) < 0) goto Err;
       +        if(sunuint32unpack(a, ea, &a, &x->count) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3entryprint(Fmt *fmt, Nfs3Entry *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3Entry");
       +        fmtprint(fmt, "\t%s=", "fileid");
       +        fmtprint(fmt, "%llud", x->fileid);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "name");
       +        fmtprint(fmt, "\"%s\"", x->name);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "cookie");
       +        fmtprint(fmt, "%llud", x->cookie);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3entrysize(Nfs3Entry *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4 + 8 + sunstringsize(x->name) + 8;
       +        return a;
       +}
       +int
       +nfs3entrypack(uchar *a, uchar *ea, uchar **pa, Nfs3Entry *x)
       +{
       +        u1int one;
       +
       +        one = 1;
       +        if(sunuint1pack(a, ea, &a, &one) < 0) goto Err;
       +        if(sunuint64pack(a, ea, &a, &x->fileid) < 0) goto Err;
       +        if(sunstringpack(a, ea, &a, &x->name, -1) < 0) goto Err;
       +        if(sunuint64pack(a, ea, &a, &x->cookie) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3entryunpack(uchar *a, uchar *ea, uchar **pa, Nfs3Entry *x)
       +{
       +        u1int one;
       +
       +        memset(x, 0, sizeof *x);
       +        if(sunuint1unpack(a, ea, &a, &one) < 0 || one != 1) goto Err;
       +        if(sunuint64unpack(a, ea, &a, &x->fileid) < 0) goto Err;
       +        if(sunstringunpack(a, ea, &a, &x->name, -1) < 0) goto Err;
       +        if(sunuint64unpack(a, ea, &a, &x->cookie) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3rreaddirprint(Fmt *fmt, Nfs3RReadDir *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3RReadDir");
       +        fmtprint(fmt, "\t%s=", "status");
       +        fmtprint(fmt, "%s", nfs3statusstr(x->status));
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "haveAttr");
       +        fmtprint(fmt, "%d", x->haveAttr);
       +        fmtprint(fmt, "\n");
       +        switch(x->haveAttr){
       +        case 1:
       +                fmtprint(fmt, "\t%s=", "attr");
       +                nfs3attrprint(fmt, &x->attr);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                fmtprint(fmt, "\t%s=", "verf");
       +                fmtprint(fmt, "%.*H", Nfs3CookieVerfSize, x->verf);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=%ud\n", "count", x->count);
       +                fmtprint(fmt, "\t%s=", "eof");
       +                fmtprint(fmt, "%d", x->eof);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +}
       +uint
       +nfs3rreaddirsize(Nfs3RReadDir *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4 + 4;
       +        switch(x->haveAttr){
       +        case 1:
       +                a = a + nfs3attrsize(&x->attr);
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                a = a + Nfs3CookieVerfSize;
       +                a += x->count;
       +                a += 4 + 4;
       +                break;
       +        }
       +        return a;
       +}
       +int
       +nfs3rreaddirpack(uchar *a, uchar *ea, uchar **pa, Nfs3RReadDir *x)
       +{
       +        int i;
       +        u1int zero;
       +
       +        if(i=x->status, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        if(sunuint1pack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +        switch(x->haveAttr){
       +        case 1:
       +                if(nfs3attrpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(sunfixedopaquepack(a, ea, &a, x->verf, Nfs3CookieVerfSize) < 0) goto Err;
       +                if(sunfixedopaquepack(a, ea, &a, x->data, x->count) < 0) goto Err;
       +                zero = 0;
       +                if(sunuint1pack(a, ea, &a, &zero) < 0) goto Err;
       +                if(sunuint1pack(a, ea, &a, &x->eof) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +static int
       +countEntry(uchar *a, uchar *ea, uchar **pa, u32int *n)
       +{
       +        uchar *oa;
       +        u64int u64;
       +        u32int u32;
       +        u1int u1;
       +
       +        oa = a;
       +        for(;;){
       +                if(sunuint1unpack(a, ea, &a, &u1) < 0)
       +                        return -1;
       +                if(u1 == 0)
       +                        break;
       +                if(sunuint64unpack(a, ea, &a, &u64) < 0
       +                || sunuint32unpack(a, ea, &a, &u32) < 0)
       +                        return -1;
       +                a += (u32+3)&~3;
       +                if(a >= ea)
       +                        return -1;
       +                if(sunuint64unpack(a, ea, &a, &u64) < 0)
       +                        return -1;
       +        }
       +        *n = (a-4) - oa;
       +        *pa = a;
       +        return 0;
       +}
       +int
       +nfs3rreaddirunpack(uchar *a, uchar *ea, uchar **pa, Nfs3RReadDir *x)
       +{
       +        int i;
       +
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->status = i;
       +        if(sunuint1unpack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +        switch(x->haveAttr){
       +        case 1:
       +                if(nfs3attrunpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        }
       +        if(x->status == Nfs3Ok){
       +                if(sunfixedopaqueunpack(a, ea, &a, x->verf, Nfs3CookieVerfSize) < 0) goto Err;
       +                x->data = a;
       +                if(countEntry(a, ea, &a, &x->count) < 0) goto Err;
       +                if(sunuint1unpack(a, ea, &a, &x->eof) < 0) goto Err;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3treaddirplusprint(Fmt *fmt, Nfs3TReadDirPlus *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3TReadDirPlus");
       +        fmtprint(fmt, "\t%s=", "handle");
       +        nfs3handleprint(fmt, &x->handle);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "cookie");
       +        fmtprint(fmt, "%llud", x->cookie);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "verf");
       +        fmtprint(fmt, "%.*H", Nfs3CookieVerfSize, x->verf);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "dirCount");
       +        fmtprint(fmt, "%ud", x->dirCount);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "maxCount");
       +        fmtprint(fmt, "%ud", x->maxCount);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3treaddirplussize(Nfs3TReadDirPlus *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + nfs3handlesize(&x->handle) + 8 + Nfs3CookieVerfSize + 4 + 4;
       +        return a;
       +}
       +int
       +nfs3treaddirpluspack(uchar *a, uchar *ea, uchar **pa, Nfs3TReadDirPlus *x)
       +{
       +        if(nfs3handlepack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(sunuint64pack(a, ea, &a, &x->cookie) < 0) goto Err;
       +        if(sunfixedopaquepack(a, ea, &a, x->verf, Nfs3CookieVerfSize) < 0) goto Err;
       +        if(sunuint32pack(a, ea, &a, &x->dirCount) < 0) goto Err;
       +        if(sunuint32pack(a, ea, &a, &x->maxCount) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3treaddirplusunpack(uchar *a, uchar *ea, uchar **pa, Nfs3TReadDirPlus *x)
       +{
       +        if(nfs3handleunpack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(sunuint64unpack(a, ea, &a, &x->cookie) < 0) goto Err;
       +        if(sunfixedopaqueunpack(a, ea, &a, x->verf, Nfs3CookieVerfSize) < 0) goto Err;
       +        if(sunuint32unpack(a, ea, &a, &x->dirCount) < 0) goto Err;
       +        if(sunuint32unpack(a, ea, &a, &x->maxCount) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3entryplusprint(Fmt *fmt, Nfs3Entry *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3EntryPlus");
       +        fmtprint(fmt, "\t%s=", "fileid");
       +        fmtprint(fmt, "%llud", x->fileid);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "name");
       +        fmtprint(fmt, "\"%s\"", x->name);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "cookie");
       +        fmtprint(fmt, "%llud", x->cookie);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "haveAttr");
       +        fmtprint(fmt, "%d", x->haveAttr);
       +        fmtprint(fmt, "\n");
       +        switch(x->haveAttr){
       +        case 1:
       +                fmtprint(fmt, "\t%s=", "attr");
       +                nfs3attrprint(fmt, &x->attr);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +        fmtprint(fmt, "\t%s=", "haveHandle");
       +        fmtprint(fmt, "%d", x->haveHandle);
       +        fmtprint(fmt, "\n");
       +        switch(x->haveHandle){
       +        case 1:
       +                fmtprint(fmt, "\t%s=", "handle");
       +                nfs3handleprint(fmt, &x->handle);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +}
       +uint
       +nfs3entryplussize(Nfs3Entry *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 8 + sunstringsize(x->name) + 8 + 4;
       +        switch(x->haveAttr){
       +        case 1:
       +                a = a + nfs3attrsize(&x->attr);
       +                break;
       +        }
       +        a = a + 4;
       +        switch(x->haveHandle){
       +        case 1:
       +                a = a + nfs3handlesize(&x->handle);
       +                break;
       +        }
       +        return a;
       +}
       +int
       +nfs3entrypluspack(uchar *a, uchar *ea, uchar **pa, Nfs3Entry *x)
       +{
       +        u1int u1;
       +
       +        if(sunuint1pack(a, ea, &a, &u1) < 0) goto Err;
       +        if(sunuint64pack(a, ea, &a, &x->fileid) < 0) goto Err;
       +        if(sunstringpack(a, ea, &a, &x->name, -1) < 0) goto Err;
       +        if(sunuint64pack(a, ea, &a, &x->cookie) < 0) goto Err;
       +        if(sunuint1pack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +        switch(x->haveAttr){
       +        case 1:
       +                if(nfs3attrpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        }
       +        if(sunuint1pack(a, ea, &a, &x->haveHandle) < 0) goto Err;
       +        switch(x->haveHandle){
       +        case 1:
       +                if(nfs3handlepack(a, ea, &a, &x->handle) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3entryplusunpack(uchar *a, uchar *ea, uchar **pa, Nfs3Entry *x)
       +{
       +        u1int u1;
       +
       +        if(sunuint1unpack(a, ea, &a, &u1) < 0 || u1 != 1) goto Err;
       +        if(sunuint64unpack(a, ea, &a, &x->fileid) < 0) goto Err;
       +        if(sunstringunpack(a, ea, &a, &x->name, -1) < 0) goto Err;
       +        if(sunuint64unpack(a, ea, &a, &x->cookie) < 0) goto Err;
       +        if(sunuint1unpack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +        switch(x->haveAttr){
       +        case 1:
       +                if(nfs3attrunpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        }
       +        if(sunuint1unpack(a, ea, &a, &x->haveHandle) < 0) goto Err;
       +        switch(x->haveHandle){
       +        case 1:
       +                if(nfs3handleunpack(a, ea, &a, &x->handle) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3rreaddirplusprint(Fmt *fmt, Nfs3RReadDirPlus *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3RReadDirPlus");
       +        fmtprint(fmt, "\t%s=", "status");
       +        fmtprint(fmt, "%s", nfs3statusstr(x->status));
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "haveAttr");
       +        fmtprint(fmt, "%d", x->haveAttr);
       +        fmtprint(fmt, "\n");
       +        switch(x->haveAttr){
       +        case 1:
       +                fmtprint(fmt, "\t%s=", "attr");
       +                nfs3attrprint(fmt, &x->attr);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                fmtprint(fmt, "\t%s=", "verf");
       +                fmtprint(fmt, "%.*H", Nfs3CookieVerfSize, x->verf);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\tcount=%ud\n", x->count);
       +                fmtprint(fmt, "\t%s=", "eof");
       +                fmtprint(fmt, "%d", x->eof);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +}
       +uint
       +nfs3rreaddirplussize(Nfs3RReadDirPlus *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4 + 4;
       +        switch(x->haveAttr){
       +        case 1:
       +                a = a + nfs3attrsize(&x->attr);
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                a = a + Nfs3CookieVerfSize;
       +                a += x->count;
       +                a += 4 + 4;
       +                break;
       +        }
       +        return a;
       +}
       +int
       +nfs3rreaddirpluspack(uchar *a, uchar *ea, uchar **pa, Nfs3RReadDirPlus *x)
       +{
       +        int i;
       +        u1int zero;
       +
       +        if(i=x->status, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        if(sunuint1pack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +        switch(x->haveAttr){
       +        case 1:
       +                if(nfs3attrpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(sunfixedopaquepack(a, ea, &a, x->verf, Nfs3CookieVerfSize) < 0) goto Err;
       +                if(sunfixedopaquepack(a, ea, &a, x->data, x->count) < 0) goto Err;
       +                zero = 0;
       +                if(sunuint1pack(a, ea, &a, &zero) < 0) goto Err;
       +                if(sunuint1pack(a, ea, &a, &x->eof) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +static int
       +countEntryPlus(uchar *a, uchar *ea, uchar **pa, u32int *n)
       +{
       +        uchar *oa;
       +        u64int u64;
       +        u32int u32;
       +        u1int u1;
       +        Nfs3Handle h;
       +        Nfs3Attr attr;
       +
       +        oa = a;
       +        for(;;){
       +                if(sunuint1unpack(a, ea, &a, &u1) < 0)
       +                        return -1;
       +                if(u1 == 0)
       +                        break;
       +                if(sunuint64unpack(a, ea, &a, &u64) < 0
       +                || sunuint32unpack(a, ea, &a, &u32) < 0)
       +                        return -1;
       +                a += (u32+3)&~3;
       +                if(a >= ea)
       +                        return -1;
       +                if(sunuint64unpack(a, ea, &a, &u64) < 0
       +                || sunuint1unpack(a, ea, &a, &u1) < 0
       +                || (u1 && nfs3attrunpack(a, ea, &a, &attr) < 0)
       +                || sunuint1unpack(a, ea, &a, &u1) < 0
       +                || (u1 && nfs3handleunpack(a, ea, &a, &h) < 0))
       +                        return -1;
       +        }
       +        *n = (a-4) - oa;
       +        *pa = a;
       +        return 0;
       +}
       +                
       +int
       +nfs3rreaddirplusunpack(uchar *a, uchar *ea, uchar **pa, Nfs3RReadDirPlus *x)
       +{
       +        int i;
       +
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->status = i;
       +        if(sunuint1unpack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +        switch(x->haveAttr){
       +        case 1:
       +                if(nfs3attrunpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        }
       +        if(x->status == Nfs3Ok){
       +                if(sunfixedopaqueunpack(a, ea, &a, x->verf, Nfs3CookieVerfSize) < 0) goto Err;
       +                x->data = a;
       +                if(countEntryPlus(a, ea, &a, &x->count) < 0) goto Err;
       +                if(sunuint1unpack(a, ea, &a, &x->eof) < 0) goto Err;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3tfsstatprint(Fmt *fmt, Nfs3TFsStat *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3TFsStat");
       +        fmtprint(fmt, "\t%s=", "handle");
       +        nfs3handleprint(fmt, &x->handle);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3tfsstatsize(Nfs3TFsStat *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + nfs3handlesize(&x->handle);
       +        return a;
       +}
       +int
       +nfs3tfsstatpack(uchar *a, uchar *ea, uchar **pa, Nfs3TFsStat *x)
       +{
       +        if(nfs3handlepack(a, ea, &a, &x->handle) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3tfsstatunpack(uchar *a, uchar *ea, uchar **pa, Nfs3TFsStat *x)
       +{
       +        if(nfs3handleunpack(a, ea, &a, &x->handle) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3rfsstatprint(Fmt *fmt, Nfs3RFsStat *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3RFsStat");
       +        fmtprint(fmt, "\t%s=", "status");
       +        fmtprint(fmt, "%s", nfs3statusstr(x->status));
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "haveAttr");
       +        fmtprint(fmt, "%d", x->haveAttr);
       +        fmtprint(fmt, "\n");
       +        switch(x->haveAttr){
       +        case 1:
       +                fmtprint(fmt, "\t%s=", "attr");
       +                nfs3attrprint(fmt, &x->attr);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                fmtprint(fmt, "\t%s=", "totalBytes");
       +                fmtprint(fmt, "%llud", x->totalBytes);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "freeBytes");
       +                fmtprint(fmt, "%llud", x->freeBytes);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "availBytes");
       +                fmtprint(fmt, "%llud", x->availBytes);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "totalFiles");
       +                fmtprint(fmt, "%llud", x->totalFiles);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "freeFiles");
       +                fmtprint(fmt, "%llud", x->freeFiles);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "availFiles");
       +                fmtprint(fmt, "%llud", x->availFiles);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "invarSec");
       +                fmtprint(fmt, "%ud", x->invarSec);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +}
       +uint
       +nfs3rfsstatsize(Nfs3RFsStat *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4 + 4;
       +        switch(x->haveAttr){
       +        case 1:
       +                a = a + nfs3attrsize(&x->attr);
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                a = a + 8 + 8 + 8 + 8 + 8 + 8 + 4;
       +                break;
       +        }
       +        return a;
       +}
       +int
       +nfs3rfsstatpack(uchar *a, uchar *ea, uchar **pa, Nfs3RFsStat *x)
       +{
       +        int i;
       +
       +        if(i=x->status, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        if(sunuint1pack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +        switch(x->haveAttr){
       +        case 1:
       +                if(nfs3attrpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(sunuint64pack(a, ea, &a, &x->totalBytes) < 0) goto Err;
       +                if(sunuint64pack(a, ea, &a, &x->freeBytes) < 0) goto Err;
       +                if(sunuint64pack(a, ea, &a, &x->availBytes) < 0) goto Err;
       +                if(sunuint64pack(a, ea, &a, &x->totalFiles) < 0) goto Err;
       +                if(sunuint64pack(a, ea, &a, &x->freeFiles) < 0) goto Err;
       +                if(sunuint64pack(a, ea, &a, &x->availFiles) < 0) goto Err;
       +                if(sunuint32pack(a, ea, &a, &x->invarSec) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3rfsstatunpack(uchar *a, uchar *ea, uchar **pa, Nfs3RFsStat *x)
       +{
       +        int i;
       +
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->status = i;
       +        if(sunuint1unpack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +        switch(x->haveAttr){
       +        case 1:
       +                if(nfs3attrunpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(sunuint64unpack(a, ea, &a, &x->totalBytes) < 0) goto Err;
       +                if(sunuint64unpack(a, ea, &a, &x->freeBytes) < 0) goto Err;
       +                if(sunuint64unpack(a, ea, &a, &x->availBytes) < 0) goto Err;
       +                if(sunuint64unpack(a, ea, &a, &x->totalFiles) < 0) goto Err;
       +                if(sunuint64unpack(a, ea, &a, &x->freeFiles) < 0) goto Err;
       +                if(sunuint64unpack(a, ea, &a, &x->availFiles) < 0) goto Err;
       +                if(sunuint32unpack(a, ea, &a, &x->invarSec) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3tfsinfoprint(Fmt *fmt, Nfs3TFsInfo *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3TFsInfo");
       +        fmtprint(fmt, "\t%s=", "handle");
       +        nfs3handleprint(fmt, &x->handle);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3tfsinfosize(Nfs3TFsInfo *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + nfs3handlesize(&x->handle);
       +        return a;
       +}
       +int
       +nfs3tfsinfopack(uchar *a, uchar *ea, uchar **pa, Nfs3TFsInfo *x)
       +{
       +        if(nfs3handlepack(a, ea, &a, &x->handle) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3tfsinfounpack(uchar *a, uchar *ea, uchar **pa, Nfs3TFsInfo *x)
       +{
       +        if(nfs3handleunpack(a, ea, &a, &x->handle) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3rfsinfoprint(Fmt *fmt, Nfs3RFsInfo *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3RFsInfo");
       +        fmtprint(fmt, "\t%s=", "status");
       +        fmtprint(fmt, "%s", nfs3statusstr(x->status));
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "haveAttr");
       +        fmtprint(fmt, "%d", x->haveAttr);
       +        fmtprint(fmt, "\n");
       +        switch(x->haveAttr){
       +        case 1:
       +                fmtprint(fmt, "\t%s=", "attr");
       +                nfs3attrprint(fmt, &x->attr);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                fmtprint(fmt, "\t%s=", "readMax");
       +                fmtprint(fmt, "%ud", x->readMax);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "readPref");
       +                fmtprint(fmt, "%ud", x->readPref);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "readMult");
       +                fmtprint(fmt, "%ud", x->readMult);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "writeMax");
       +                fmtprint(fmt, "%ud", x->writeMax);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "writePref");
       +                fmtprint(fmt, "%ud", x->writePref);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "writeMult");
       +                fmtprint(fmt, "%ud", x->writeMult);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "readDirPref");
       +                fmtprint(fmt, "%ud", x->readDirPref);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "maxFileSize");
       +                fmtprint(fmt, "%llud", x->maxFileSize);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "timePrec");
       +                nfs3timeprint(fmt, &x->timePrec);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "flags");
       +                fmtprint(fmt, "%ud", x->flags);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +}
       +uint
       +nfs3rfsinfosize(Nfs3RFsInfo *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4 + 4;
       +        switch(x->haveAttr){
       +        case 1:
       +                a = a + nfs3attrsize(&x->attr);
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                a = a + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 8 + nfs3timesize(&x->timePrec) + 4;
       +                break;
       +        }
       +        return a;
       +}
       +int
       +nfs3rfsinfopack(uchar *a, uchar *ea, uchar **pa, Nfs3RFsInfo *x)
       +{
       +        int i;
       +
       +        if(i=x->status, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        if(sunuint1pack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +        switch(x->haveAttr){
       +        case 1:
       +                if(nfs3attrpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(sunuint32pack(a, ea, &a, &x->readMax) < 0) goto Err;
       +                if(sunuint32pack(a, ea, &a, &x->readPref) < 0) goto Err;
       +                if(sunuint32pack(a, ea, &a, &x->readMult) < 0) goto Err;
       +                if(sunuint32pack(a, ea, &a, &x->writeMax) < 0) goto Err;
       +                if(sunuint32pack(a, ea, &a, &x->writePref) < 0) goto Err;
       +                if(sunuint32pack(a, ea, &a, &x->writeMult) < 0) goto Err;
       +                if(sunuint32pack(a, ea, &a, &x->readDirPref) < 0) goto Err;
       +                if(sunuint64pack(a, ea, &a, &x->maxFileSize) < 0) goto Err;
       +                if(nfs3timepack(a, ea, &a, &x->timePrec) < 0) goto Err;
       +                if(sunuint32pack(a, ea, &a, &x->flags) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3rfsinfounpack(uchar *a, uchar *ea, uchar **pa, Nfs3RFsInfo *x)
       +{
       +        int i;
       +
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->status = i;
       +        if(sunuint1unpack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +        switch(x->haveAttr){
       +        case 1:
       +                if(nfs3attrunpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(sunuint32unpack(a, ea, &a, &x->readMax) < 0) goto Err;
       +                if(sunuint32unpack(a, ea, &a, &x->readPref) < 0) goto Err;
       +                if(sunuint32unpack(a, ea, &a, &x->readMult) < 0) goto Err;
       +                if(sunuint32unpack(a, ea, &a, &x->writeMax) < 0) goto Err;
       +                if(sunuint32unpack(a, ea, &a, &x->writePref) < 0) goto Err;
       +                if(sunuint32unpack(a, ea, &a, &x->writeMult) < 0) goto Err;
       +                if(sunuint32unpack(a, ea, &a, &x->readDirPref) < 0) goto Err;
       +                if(sunuint64unpack(a, ea, &a, &x->maxFileSize) < 0) goto Err;
       +                if(nfs3timeunpack(a, ea, &a, &x->timePrec) < 0) goto Err;
       +                if(sunuint32unpack(a, ea, &a, &x->flags) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3tpathconfprint(Fmt *fmt, Nfs3TPathconf *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3TPathconf");
       +        fmtprint(fmt, "\t%s=", "handle");
       +        nfs3handleprint(fmt, &x->handle);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3tpathconfsize(Nfs3TPathconf *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + nfs3handlesize(&x->handle);
       +        return a;
       +}
       +int
       +nfs3tpathconfpack(uchar *a, uchar *ea, uchar **pa, Nfs3TPathconf *x)
       +{
       +        if(nfs3handlepack(a, ea, &a, &x->handle) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3tpathconfunpack(uchar *a, uchar *ea, uchar **pa, Nfs3TPathconf *x)
       +{
       +        if(nfs3handleunpack(a, ea, &a, &x->handle) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3rpathconfprint(Fmt *fmt, Nfs3RPathconf *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3RPathconf");
       +        fmtprint(fmt, "\t%s=", "status");
       +        fmtprint(fmt, "%s", nfs3statusstr(x->status));
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "haveAttr");
       +        fmtprint(fmt, "%d", x->haveAttr);
       +        fmtprint(fmt, "\n");
       +        switch(x->haveAttr){
       +        case 1:
       +                fmtprint(fmt, "\t%s=", "attr");
       +                nfs3attrprint(fmt, &x->attr);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                fmtprint(fmt, "\t%s=", "maxLink");
       +                fmtprint(fmt, "%ud", x->maxLink);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "maxName");
       +                fmtprint(fmt, "%ud", x->maxName);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "noTrunc");
       +                fmtprint(fmt, "%d", x->noTrunc);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "chownRestricted");
       +                fmtprint(fmt, "%d", x->chownRestricted);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "caseInsensitive");
       +                fmtprint(fmt, "%d", x->caseInsensitive);
       +                fmtprint(fmt, "\n");
       +                fmtprint(fmt, "\t%s=", "casePreserving");
       +                fmtprint(fmt, "%d", x->casePreserving);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +}
       +uint
       +nfs3rpathconfsize(Nfs3RPathconf *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4 + 4;
       +        switch(x->haveAttr){
       +        case 1:
       +                a = a + nfs3attrsize(&x->attr);
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                a = a + 4 + 4 + 4 + 4 + 4 + 4;
       +                break;
       +        }
       +        return a;
       +}
       +int
       +nfs3rpathconfpack(uchar *a, uchar *ea, uchar **pa, Nfs3RPathconf *x)
       +{
       +        int i;
       +
       +        if(i=x->status, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        if(sunuint1pack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +        switch(x->haveAttr){
       +        case 1:
       +                if(nfs3attrpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(sunuint32pack(a, ea, &a, &x->maxLink) < 0) goto Err;
       +                if(sunuint32pack(a, ea, &a, &x->maxName) < 0) goto Err;
       +                if(sunuint1pack(a, ea, &a, &x->noTrunc) < 0) goto Err;
       +                if(sunuint1pack(a, ea, &a, &x->chownRestricted) < 0) goto Err;
       +                if(sunuint1pack(a, ea, &a, &x->caseInsensitive) < 0) goto Err;
       +                if(sunuint1pack(a, ea, &a, &x->casePreserving) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3rpathconfunpack(uchar *a, uchar *ea, uchar **pa, Nfs3RPathconf *x)
       +{
       +        int i;
       +
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->status = i;
       +        if(sunuint1unpack(a, ea, &a, &x->haveAttr) < 0) goto Err;
       +        switch(x->haveAttr){
       +        case 1:
       +                if(nfs3attrunpack(a, ea, &a, &x->attr) < 0) goto Err;
       +                break;
       +        }
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(sunuint32unpack(a, ea, &a, &x->maxLink) < 0) goto Err;
       +                if(sunuint32unpack(a, ea, &a, &x->maxName) < 0) goto Err;
       +                if(sunuint1unpack(a, ea, &a, &x->noTrunc) < 0) goto Err;
       +                if(sunuint1unpack(a, ea, &a, &x->chownRestricted) < 0) goto Err;
       +                if(sunuint1unpack(a, ea, &a, &x->caseInsensitive) < 0) goto Err;
       +                if(sunuint1unpack(a, ea, &a, &x->casePreserving) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3tcommitprint(Fmt *fmt, Nfs3TCommit *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3TCommit");
       +        fmtprint(fmt, "\t%s=", "handle");
       +        nfs3handleprint(fmt, &x->handle);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "offset");
       +        fmtprint(fmt, "%llud", x->offset);
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "count");
       +        fmtprint(fmt, "%ud", x->count);
       +        fmtprint(fmt, "\n");
       +}
       +uint
       +nfs3tcommitsize(Nfs3TCommit *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + nfs3handlesize(&x->handle) + 8 + 4;
       +        return a;
       +}
       +int
       +nfs3tcommitpack(uchar *a, uchar *ea, uchar **pa, Nfs3TCommit *x)
       +{
       +        if(nfs3handlepack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(sunuint64pack(a, ea, &a, &x->offset) < 0) goto Err;
       +        if(sunuint32pack(a, ea, &a, &x->count) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3tcommitunpack(uchar *a, uchar *ea, uchar **pa, Nfs3TCommit *x)
       +{
       +        if(nfs3handleunpack(a, ea, &a, &x->handle) < 0) goto Err;
       +        if(sunuint64unpack(a, ea, &a, &x->offset) < 0) goto Err;
       +        if(sunuint32unpack(a, ea, &a, &x->count) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +void
       +nfs3rcommitprint(Fmt *fmt, Nfs3RCommit *x)
       +{
       +        fmtprint(fmt, "%s\n", "Nfs3RCommit");
       +        fmtprint(fmt, "\t%s=", "status");
       +        fmtprint(fmt, "%s", nfs3statusstr(x->status));
       +        fmtprint(fmt, "\n");
       +        fmtprint(fmt, "\t%s=", "wcc");
       +        nfs3wccprint(fmt, &x->wcc);
       +        fmtprint(fmt, "\n");
       +        switch(x->status){
       +        case Nfs3Ok:
       +                fmtprint(fmt, "\t%s=", "verf");
       +                fmtprint(fmt, "%.*H", Nfs3WriteVerfSize, x->verf);
       +                fmtprint(fmt, "\n");
       +                break;
       +        }
       +}
       +uint
       +nfs3rcommitsize(Nfs3RCommit *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4 + nfs3wccsize(&x->wcc);
       +        switch(x->status){
       +        case Nfs3Ok:
       +                a = a + Nfs3WriteVerfSize;
       +                break;
       +        }
       +        return a;
       +}
       +int
       +nfs3rcommitpack(uchar *a, uchar *ea, uchar **pa, Nfs3RCommit *x)
       +{
       +        int i;
       +
       +        if(i=x->status, sunenumpack(a, ea, &a, &i) < 0) goto Err;
       +        if(nfs3wccpack(a, ea, &a, &x->wcc) < 0) goto Err;
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(sunfixedopaquepack(a, ea, &a, x->verf, Nfs3WriteVerfSize) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +int
       +nfs3rcommitunpack(uchar *a, uchar *ea, uchar **pa, Nfs3RCommit *x)
       +{
       +        int i;
       +
       +        if(sunenumunpack(a, ea, &a, &i) < 0) goto Err; x->status = i;
       +        if(nfs3wccunpack(a, ea, &a, &x->wcc) < 0) goto Err;
       +        switch(x->status){
       +        case Nfs3Ok:
       +                if(sunfixedopaqueunpack(a, ea, &a, x->verf, Nfs3WriteVerfSize) < 0) goto Err;
       +                break;
       +        }
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +
       +typedef int (*P)(uchar*, uchar*, uchar**, SunCall*);
       +typedef void (*F)(Fmt*, SunCall*);
       +typedef uint (*S)(SunCall*);
       +
       +static SunProc proc[] = {
       +        (P)nfs3tnullpack, (P)nfs3tnullunpack, (S)nfs3tnullsize, (F)nfs3tnullprint, sizeof(Nfs3TNull),
       +        (P)nfs3rnullpack, (P)nfs3rnullunpack, (S)nfs3rnullsize, (F)nfs3rnullprint, sizeof(Nfs3RNull),
       +        (P)nfs3tgetattrpack, (P)nfs3tgetattrunpack, (S)nfs3tgetattrsize, (F)nfs3tgetattrprint, sizeof(Nfs3TGetattr),
       +        (P)nfs3rgetattrpack, (P)nfs3rgetattrunpack, (S)nfs3rgetattrsize, (F)nfs3rgetattrprint, sizeof(Nfs3RGetattr),
       +        (P)nfs3tsetattrpack, (P)nfs3tsetattrunpack, (S)nfs3tsetattrsize, (F)nfs3tsetattrprint, sizeof(Nfs3TSetattr),
       +        (P)nfs3rsetattrpack, (P)nfs3rsetattrunpack, (S)nfs3rsetattrsize, (F)nfs3rsetattrprint, sizeof(Nfs3RSetattr),
       +        (P)nfs3tlookuppack, (P)nfs3tlookupunpack, (S)nfs3tlookupsize, (F)nfs3tlookupprint, sizeof(Nfs3TLookup),
       +        (P)nfs3rlookuppack, (P)nfs3rlookupunpack, (S)nfs3rlookupsize, (F)nfs3rlookupprint, sizeof(Nfs3RLookup),
       +        (P)nfs3taccesspack, (P)nfs3taccessunpack, (S)nfs3taccesssize, (F)nfs3taccessprint, sizeof(Nfs3TAccess),
       +        (P)nfs3raccesspack, (P)nfs3raccessunpack, (S)nfs3raccesssize, (F)nfs3raccessprint, sizeof(Nfs3RAccess),
       +        (P)nfs3treadlinkpack, (P)nfs3treadlinkunpack, (S)nfs3treadlinksize, (F)nfs3treadlinkprint, sizeof(Nfs3TReadlink),
       +        (P)nfs3rreadlinkpack, (P)nfs3rreadlinkunpack, (S)nfs3rreadlinksize, (F)nfs3rreadlinkprint, sizeof(Nfs3RReadlink),
       +        (P)nfs3treadpack, (P)nfs3treadunpack, (S)nfs3treadsize, (F)nfs3treadprint, sizeof(Nfs3TRead),
       +        (P)nfs3rreadpack, (P)nfs3rreadunpack, (S)nfs3rreadsize, (F)nfs3rreadprint, sizeof(Nfs3RRead),
       +        (P)nfs3twritepack, (P)nfs3twriteunpack, (S)nfs3twritesize, (F)nfs3twriteprint, sizeof(Nfs3TWrite),
       +        (P)nfs3rwritepack, (P)nfs3rwriteunpack, (S)nfs3rwritesize, (F)nfs3rwriteprint, sizeof(Nfs3RWrite),
       +        (P)nfs3tcreatepack, (P)nfs3tcreateunpack, (S)nfs3tcreatesize, (F)nfs3tcreateprint, sizeof(Nfs3TCreate),
       +        (P)nfs3rcreatepack, (P)nfs3rcreateunpack, (S)nfs3rcreatesize, (F)nfs3rcreateprint, sizeof(Nfs3RCreate),
       +        (P)nfs3tmkdirpack, (P)nfs3tmkdirunpack, (S)nfs3tmkdirsize, (F)nfs3tmkdirprint, sizeof(Nfs3TMkdir),
       +        (P)nfs3rmkdirpack, (P)nfs3rmkdirunpack, (S)nfs3rmkdirsize, (F)nfs3rmkdirprint, sizeof(Nfs3RMkdir),
       +        (P)nfs3tsymlinkpack, (P)nfs3tsymlinkunpack, (S)nfs3tsymlinksize, (F)nfs3tsymlinkprint, sizeof(Nfs3TSymlink),
       +        (P)nfs3rsymlinkpack, (P)nfs3rsymlinkunpack, (S)nfs3rsymlinksize, (F)nfs3rsymlinkprint, sizeof(Nfs3RSymlink),
       +        (P)nfs3tmknodpack, (P)nfs3tmknodunpack, (S)nfs3tmknodsize, (F)nfs3tmknodprint, sizeof(Nfs3TMknod),
       +        (P)nfs3rmknodpack, (P)nfs3rmknodunpack, (S)nfs3rmknodsize, (F)nfs3rmknodprint, sizeof(Nfs3RMknod),
       +        (P)nfs3tremovepack, (P)nfs3tremoveunpack, (S)nfs3tremovesize, (F)nfs3tremoveprint, sizeof(Nfs3TRemove),
       +        (P)nfs3rremovepack, (P)nfs3rremoveunpack, (S)nfs3rremovesize, (F)nfs3rremoveprint, sizeof(Nfs3RRemove),
       +        (P)nfs3trmdirpack, (P)nfs3trmdirunpack, (S)nfs3trmdirsize, (F)nfs3trmdirprint, sizeof(Nfs3TRmdir),
       +        (P)nfs3rrmdirpack, (P)nfs3rrmdirunpack, (S)nfs3rrmdirsize, (F)nfs3rrmdirprint, sizeof(Nfs3RRmdir),
       +        (P)nfs3trenamepack, (P)nfs3trenameunpack, (S)nfs3trenamesize, (F)nfs3trenameprint, sizeof(Nfs3TRename),
       +        (P)nfs3rrenamepack, (P)nfs3rrenameunpack, (S)nfs3rrenamesize, (F)nfs3rrenameprint, sizeof(Nfs3RRename),
       +        (P)nfs3tlinkpack, (P)nfs3tlinkunpack, (S)nfs3tlinksize, (F)nfs3tlinkprint, sizeof(Nfs3TLink),
       +        (P)nfs3rlinkpack, (P)nfs3rlinkunpack, (S)nfs3rlinksize, (F)nfs3rlinkprint, sizeof(Nfs3RLink),
       +        (P)nfs3treaddirpack, (P)nfs3treaddirunpack, (S)nfs3treaddirsize, (F)nfs3treaddirprint, sizeof(Nfs3TReadDir),
       +        (P)nfs3rreaddirpack, (P)nfs3rreaddirunpack, (S)nfs3rreaddirsize, (F)nfs3rreaddirprint, sizeof(Nfs3RReadDir),
       +        (P)nfs3treaddirpluspack, (P)nfs3treaddirplusunpack, (S)nfs3treaddirplussize, (F)nfs3treaddirplusprint, sizeof(Nfs3TReadDirPlus),
       +        (P)nfs3rreaddirpluspack, (P)nfs3rreaddirplusunpack, (S)nfs3rreaddirplussize, (F)nfs3rreaddirplusprint, sizeof(Nfs3RReadDirPlus),
       +        (P)nfs3tfsstatpack, (P)nfs3tfsstatunpack, (S)nfs3tfsstatsize, (F)nfs3tfsstatprint, sizeof(Nfs3TFsStat),
       +        (P)nfs3rfsstatpack, (P)nfs3rfsstatunpack, (S)nfs3rfsstatsize, (F)nfs3rfsstatprint, sizeof(Nfs3RFsStat),
       +        (P)nfs3tfsinfopack, (P)nfs3tfsinfounpack, (S)nfs3tfsinfosize, (F)nfs3tfsinfoprint, sizeof(Nfs3TFsInfo),
       +        (P)nfs3rfsinfopack, (P)nfs3rfsinfounpack, (S)nfs3rfsinfosize, (F)nfs3rfsinfoprint, sizeof(Nfs3RFsInfo),
       +        (P)nfs3tpathconfpack, (P)nfs3tpathconfunpack, (S)nfs3tpathconfsize, (F)nfs3tpathconfprint, sizeof(Nfs3TPathconf),
       +        (P)nfs3rpathconfpack, (P)nfs3rpathconfunpack, (S)nfs3rpathconfsize, (F)nfs3rpathconfprint, sizeof(Nfs3RPathconf),
       +        (P)nfs3tcommitpack, (P)nfs3tcommitunpack, (S)nfs3tcommitsize, (F)nfs3tcommitprint, sizeof(Nfs3TCommit),
       +        (P)nfs3rcommitpack, (P)nfs3rcommitunpack, (S)nfs3rcommitsize, (F)nfs3rcommitprint, sizeof(Nfs3RCommit)
       +};
       +
       +SunProg nfs3prog = 
       +{
       +        Nfs3Program,
       +        Nfs3Version,
       +        proc,
       +        nelem(proc),
       +};
 (DIR) diff --git a/src/libsunrpc/portmap.c b/src/libsunrpc/portmap.c
       t@@ -0,0 +1,498 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <thread.h>
       +#include <sunrpc.h>
       +
       +static void
       +portMapPrint(Fmt *fmt, PortMap *x)
       +{
       +        fmtprint(fmt, "[%ud %ud %ud %ud]", x->prog, x->vers, x->prot, x->port);
       +}
       +static uint
       +portMapSize(PortMap *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4 + 4 + 4 + 4;
       +        return a;
       +}
       +static int
       +portMapPack(uchar *a, uchar *ea, uchar **pa, PortMap *x)
       +{
       +        if(sunuint32pack(a, ea, &a, &x->prog) < 0) goto Err;
       +        if(sunuint32pack(a, ea, &a, &x->vers) < 0) goto Err;
       +        if(sunuint32pack(a, ea, &a, &x->prot) < 0) goto Err;
       +        if(sunuint32pack(a, ea, &a, &x->port) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +static int
       +portMapUnpack(uchar *a, uchar *ea, uchar **pa, PortMap *x)
       +{
       +        if(sunuint32unpack(a, ea, &a, &x->prog) < 0) goto Err;
       +        if(sunuint32unpack(a, ea, &a, &x->vers) < 0) goto Err;
       +        if(sunuint32unpack(a, ea, &a, &x->prot) < 0) goto Err;
       +        if(sunuint32unpack(a, ea, &a, &x->port) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +static void
       +portTNullPrint(Fmt *fmt, PortTNull *x)
       +{
       +        USED(x);
       +        fmtprint(fmt, "%s", "PortTNull");
       +}
       +static uint
       +portTNullSize(PortTNull *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0;
       +        return a;
       +}
       +static int
       +portTNullPack(uchar *a, uchar *ea, uchar **pa, PortTNull *x)
       +{
       +        USED(ea);
       +        USED(x);
       +        *pa = a;
       +        return 0;
       +}
       +static int
       +portTNullUnpack(uchar *a, uchar *ea, uchar **pa, PortTNull *x)
       +{
       +        USED(ea);
       +        USED(x);
       +        *pa = a;
       +        return 0;
       +}
       +static void
       +portRNullPrint(Fmt *fmt, PortRNull *x)
       +{
       +        USED(x);
       +        fmtprint(fmt, "%s", "PortRNull");
       +}
       +static uint
       +portRNullSize(PortRNull *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0;
       +        return a;
       +}
       +static int
       +portRNullPack(uchar *a, uchar *ea, uchar **pa, PortRNull *x)
       +{
       +        USED(ea);
       +        USED(x);
       +        *pa = a;
       +        return 0;
       +}
       +static int
       +portRNullUnpack(uchar *a, uchar *ea, uchar **pa, PortRNull *x)
       +{
       +        USED(ea);
       +        USED(x);
       +        *pa = a;
       +        return 0;
       +}
       +static void
       +portTSetPrint(Fmt *fmt, PortTSet *x)
       +{
       +        fmtprint(fmt, "PortTSet ");
       +        portMapPrint(fmt, &x->map);
       +}
       +static uint
       +portTSetSize(PortTSet *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + portMapSize(&x->map);
       +        return a;
       +}
       +static int
       +portTSetPack(uchar *a, uchar *ea, uchar **pa, PortTSet *x)
       +{
       +        if(portMapPack(a, ea, &a, &x->map) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +static int
       +portTSetUnpack(uchar *a, uchar *ea, uchar **pa, PortTSet *x)
       +{
       +        if(portMapUnpack(a, ea, &a, &x->map) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +static void
       +portRSetPrint(Fmt *fmt, PortRSet *x)
       +{
       +        fmtprint(fmt, "PortRSet %ud", x->b);
       +}
       +static uint
       +portRSetSize(PortRSet *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4;
       +        return a;
       +}
       +static int
       +portRSetPack(uchar *a, uchar *ea, uchar **pa, PortRSet *x)
       +{
       +        if(sunuint1pack(a, ea, &a, &x->b) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +static int
       +portRSetUnpack(uchar *a, uchar *ea, uchar **pa, PortRSet *x)
       +{
       +        if(sunuint1unpack(a, ea, &a, &x->b) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +static void
       +portTUnsetPrint(Fmt *fmt, PortTUnset *x)
       +{
       +        fmtprint(fmt, "PortTUnset ");
       +        portMapPrint(fmt, &x->map);
       +}
       +static uint
       +portTUnsetSize(PortTUnset *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + portMapSize(&x->map);
       +        return a;
       +}
       +static int
       +portTUnsetPack(uchar *a, uchar *ea, uchar **pa, PortTUnset *x)
       +{
       +        if(portMapPack(a, ea, &a, &x->map) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +static int
       +portTUnsetUnpack(uchar *a, uchar *ea, uchar **pa, PortTUnset *x)
       +{
       +        if(portMapUnpack(a, ea, &a, &x->map) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +static void
       +portRUnsetPrint(Fmt *fmt, PortRUnset *x)
       +{
       +        fmtprint(fmt, "PortRUnset %ud", x->b);
       +}
       +static uint
       +portRUnsetSize(PortRUnset *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4;
       +        return a;
       +}
       +static int
       +portRUnsetPack(uchar *a, uchar *ea, uchar **pa, PortRUnset *x)
       +{
       +        if(sunuint1pack(a, ea, &a, &x->b) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +static int
       +portRUnsetUnpack(uchar *a, uchar *ea, uchar **pa, PortRUnset *x)
       +{
       +        if(sunuint1unpack(a, ea, &a, &x->b) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +static void
       +portTGetportPrint(Fmt *fmt, PortTGetport *x)
       +{
       +        fmtprint(fmt, "PortTGetport ");
       +        portMapPrint(fmt, &x->map);
       +}
       +static uint
       +portTGetportSize(PortTGetport *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + portMapSize(&x->map);
       +        return a;
       +}
       +static int
       +portTGetportPack(uchar *a, uchar *ea, uchar **pa, PortTGetport *x)
       +{
       +        if(portMapPack(a, ea, &a, &x->map) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +static int
       +portTGetportUnpack(uchar *a, uchar *ea, uchar **pa, PortTGetport *x)
       +{
       +        if(portMapUnpack(a, ea, &a, &x->map) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +static void
       +portRGetportPrint(Fmt *fmt, PortRGetport *x)
       +{
       +        fmtprint(fmt, "PortRGetport %ud", x->port);
       +}
       +static uint
       +portRGetportSize(PortRGetport *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4;
       +        return a;
       +}
       +static int
       +portRGetportPack(uchar *a, uchar *ea, uchar **pa, PortRGetport *x)
       +{
       +        if(sunuint32pack(a, ea, &a, &x->port) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +static int
       +portRGetportUnpack(uchar *a, uchar *ea, uchar **pa, PortRGetport *x)
       +{
       +        if(sunuint32unpack(a, ea, &a, &x->port) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +static void
       +portTDumpPrint(Fmt *fmt, PortTDump *x)
       +{
       +        USED(x);
       +        fmtprint(fmt, "PortTDump");
       +}
       +static uint
       +portTDumpSize(PortTDump *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0;
       +        return a;
       +}
       +static int
       +portTDumpPack(uchar *a, uchar *ea, uchar **pa, PortTDump *x)
       +{
       +        USED(ea);
       +        USED(x);
       +        *pa = a;
       +        return 0;
       +}
       +static int
       +portTDumpUnpack(uchar *a, uchar *ea, uchar **pa, PortTDump *x)
       +{
       +        USED(ea);
       +        USED(x);
       +        *pa = a;
       +        return 0;
       +}
       +static void
       +portRDumpPrint(Fmt *fmt, PortRDump *x)
       +{
       +        int i;
       +
       +        fmtprint(fmt, "PortRDump");
       +        for(i=0; i<x->nmap; i++){
       +                fmtprint(fmt, " ");
       +                portMapPrint(fmt, &x->map[i]);
       +        }
       +}
       +static uint
       +portRDumpSize(PortRDump *x)
       +{
       +        return (5*4*x->nmap) + 4;
       +}
       +static int
       +portRDumpPack(uchar *a, uchar *ea, uchar **pa, PortRDump *x)
       +{
       +        int i;
       +        u32int zero, one;
       +
       +        zero = 0;
       +        one = 1;
       +        for(i=0; i<x->nmap; i++){
       +                if(sunuint32pack(a, ea, &a, &one) < 0
       +                || portMapPack(a, ea, &a, &x->map[i]) < 0)
       +                        goto Err;
       +        }
       +        if(sunuint32pack(a, ea, &a, &zero) < 0)
       +                goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +static int
       +portRDumpUnpack(uchar *a, uchar *ea, uchar **pa, PortRDump *x)
       +{
       +        int i;
       +        u1int u1;
       +        PortMap *m;
       +
       +        m = (PortMap*)a;
       +        for(i=0;; i++){
       +                if(sunuint1unpack(a, ea, &a, &u1) < 0)
       +                        goto Err;
       +                if(u1 == 0)
       +                        break;
       +                if(portMapUnpack(a, ea, &a, &m[i]) < 0)
       +                        goto Err;
       +        }
       +        x->nmap = i;
       +        x->map = m;
       +        *pa = a;
       +        return 0;
       +
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +static void
       +portTCallitPrint(Fmt *fmt, PortTCallit *x)
       +{
       +        fmtprint(fmt, "PortTCallit [%ud,%ud,%ud] %ud", x->prog, x->vers, x->proc, x->count);
       +}
       +static uint
       +portTCallitSize(PortTCallit *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4 + 4 + 4 + sunvaropaquesize(x->count);
       +        return a;
       +}
       +static int
       +portTCallitPack(uchar *a, uchar *ea, uchar **pa, PortTCallit *x)
       +{
       +        if(sunuint32pack(a, ea, &a, &x->prog) < 0) goto Err;
       +        if(sunuint32pack(a, ea, &a, &x->vers) < 0) goto Err;
       +        if(sunuint32pack(a, ea, &a, &x->proc) < 0) goto Err;
       +        if(sunvaropaquepack(a, ea, &a, &x->data, &x->count, -1) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +static int
       +portTCallitUnpack(uchar *a, uchar *ea, uchar **pa, PortTCallit *x)
       +{
       +        if(sunuint32unpack(a, ea, &a, &x->prog) < 0) goto Err;
       +        if(sunuint32unpack(a, ea, &a, &x->vers) < 0) goto Err;
       +        if(sunuint32unpack(a, ea, &a, &x->proc) < 0) goto Err;
       +        if(sunvaropaqueunpack(a, ea, &a, &x->data, &x->count, -1) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +static void
       +portRCallitPrint(Fmt *fmt, PortRCallit *x)
       +{
       +        fmtprint(fmt, "PortRCallit %ud %ud", x->port, x->count);
       +}
       +static uint
       +portRCallitSize(PortRCallit *x)
       +{
       +        uint a;
       +        USED(x);
       +        a = 0 + 4 + sunvaropaquesize(x->count);
       +        return a;
       +}
       +static int
       +portRCallitPack(uchar *a, uchar *ea, uchar **pa, PortRCallit *x)
       +{
       +        if(sunuint32pack(a, ea, &a, &x->port) < 0) goto Err;
       +        if(sunvaropaquepack(a, ea, &a, &x->data, &x->count, -1) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +static int
       +portRCallitUnpack(uchar *a, uchar *ea, uchar **pa, PortRCallit *x)
       +{
       +        if(sunuint32unpack(a, ea, &a, &x->port) < 0) goto Err;
       +        if(sunvaropaqueunpack(a, ea, &a, &x->data, &x->count, -1) < 0) goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +
       +typedef int (*P)(uchar*, uchar*, uchar**, SunCall*);
       +typedef void (*F)(Fmt*, SunCall*);
       +typedef uint (*S)(SunCall*);
       +
       +static SunProc proc[] = {
       +        (P)portTNullPack, (P)portTNullUnpack, (S)portTNullSize, (F)portTNullPrint, sizeof(PortTNull),
       +        (P)portRNullPack, (P)portRNullUnpack, (S)portRNullSize, (F)portRNullPrint, sizeof(PortRNull),
       +        (P)portTSetPack, (P)portTSetUnpack, (S)portTSetSize, (F)portTSetPrint, sizeof(PortTSet),
       +        (P)portRSetPack, (P)portRSetUnpack, (S)portRSetSize, (F)portRSetPrint, sizeof(PortRSet),
       +        (P)portTUnsetPack, (P)portTUnsetUnpack, (S)portTUnsetSize, (F)portTUnsetPrint, sizeof(PortTUnset),
       +        (P)portRUnsetPack, (P)portRUnsetUnpack, (S)portRUnsetSize, (F)portRUnsetPrint, sizeof(PortRUnset),
       +        (P)portTGetportPack, (P)portTGetportUnpack, (S)portTGetportSize, (F)portTGetportPrint, sizeof(PortTGetport),
       +        (P)portRGetportPack, (P)portRGetportUnpack, (S)portRGetportSize, (F)portRGetportPrint, sizeof(PortRGetport),
       +        (P)portTDumpPack, (P)portTDumpUnpack, (S)portTDumpSize, (F)portTDumpPrint, sizeof(PortTDump),
       +        (P)portRDumpPack, (P)portRDumpUnpack, (S)portRDumpSize, (F)portRDumpPrint, sizeof(PortRDump),
       +        (P)portTCallitPack, (P)portTCallitUnpack, (S)portTCallitSize, (F)portTCallitPrint, sizeof(PortTCallit),
       +        (P)portRCallitPack, (P)portRCallitUnpack, (S)portRCallitSize, (F)portRCallitPrint, sizeof(PortRCallit),
       +};
       +
       +SunProg portProg = 
       +{
       +        PortProgram,
       +        PortVersion,
       +        proc,
       +        nelem(proc),
       +};
 (DIR) diff --git a/src/libsunrpc/prog.c b/src/libsunrpc/prog.c
       t@@ -0,0 +1,74 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <thread.h>
       +#include <sunrpc.h>
       +
       +SunStatus
       +suncallpack(SunProg *prog, uchar *a, uchar *ea, uchar **pa, SunCall *c)
       +{
       +        uchar *x;
       +        int (*pack)(uchar*, uchar*, uchar**, SunCall*);
       +
       +        if(pa == nil)
       +                pa = &x;
       +        if(c->type < 0 || c->type >= prog->nproc || (pack=prog->proc[c->type].pack) == nil)
       +                return SunProcUnavail;
       +        if((*pack)(a, ea, pa, c) < 0)
       +                return SunGarbageArgs;
       +        return SunSuccess;
       +}
       +
       +SunStatus
       +suncallunpack(SunProg *prog, uchar *a, uchar *ea, uchar **pa, SunCall *c)
       +{
       +        uchar *x;
       +        int (*unpack)(uchar*, uchar*, uchar**, SunCall*);
       +
       +        if(pa == nil)
       +                pa = &x;
       +        if(c->type < 0 || c->type >= prog->nproc || (unpack=prog->proc[c->type].unpack) == nil)
       +                return SunProcUnavail;
       +        if((*unpack)(a, ea, pa, c) < 0){
       +                fprint(2, "%lud %d: %.*H unpack failed\n", prog->prog, c->type, (int)(ea-a), a);
       +                return SunGarbageArgs;
       +        }
       +        return SunSuccess;
       +}
       +
       +SunStatus
       +suncallunpackalloc(SunProg *prog, SunCallType type, uchar *a, uchar *ea, uchar **pa, SunCall **pc)
       +{
       +        uchar *x;
       +        uint size;
       +        int (*unpack)(uchar*, uchar*, uchar**, SunCall*);
       +        SunCall *c;
       +
       +        if(pa == nil)
       +                pa = &x;
       +        if(type < 0 || type >= prog->nproc || (unpack=prog->proc[type].unpack) == nil)
       +                return SunProcUnavail;
       +        size = prog->proc[type].sizeoftype;
       +        if(size == 0)
       +                return SunProcUnavail;
       +        c = mallocz(size, 1);
       +        if(c == nil)
       +                return SunSystemErr;
       +        c->type = type;
       +        if((*unpack)(a, ea, pa, c) < 0){
       +                fprint(2, "in: %.*H unpack failed\n", (int)(ea-a), a);
       +                free(c);
       +                return SunGarbageArgs;
       +        }
       +        *pc = c;
       +        return SunSuccess;
       +}
       +
       +uint
       +suncallsize(SunProg *prog, SunCall *c)
       +{
       +        uint (*size)(SunCall*);
       +
       +        if(c->type < 0 || c->type >= prog->nproc || (size=prog->proc[c->type].size) == nil)
       +                return ~0;
       +        return (*size)(c);
       +}
 (DIR) diff --git a/src/libsunrpc/rpc.c b/src/libsunrpc/rpc.c
       t@@ -0,0 +1,528 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <thread.h>
       +#include <sunrpc.h>
       +
       +/*
       + * RPC protocol constants
       + */
       +enum
       +{
       +        RpcVersion = 2,
       +
       +        /* msg type */
       +        MsgCall = 0,
       +        MsgReply = 1,
       +
       +        /* reply stat */
       +        MsgAccepted = 0,
       +        MsgDenied = 1,
       +
       +        /* accept stat */
       +        MsgSuccess = 0,
       +        MsgProgUnavail = 1,
       +        MsgProgMismatch = 2,
       +        MsgProcUnavail = 3,
       +        MsgGarbageArgs = 4,
       +        MsgSystemErr = 5,
       +
       +        /* reject stat */
       +        MsgRpcMismatch = 0,
       +        MsgAuthError = 1,
       +
       +        /* msg auth xxx */
       +        MsgAuthOk = 0,
       +        MsgAuthBadCred = 1,
       +        MsgAuthRejectedCred = 2,
       +        MsgAuthBadVerf = 3,
       +        MsgAuthRejectedVerf = 4,
       +        MsgAuthTooWeak = 5,
       +        MsgAuthInvalidResp = 6,
       +        MsgAuthFailed = 7,
       +};
       +
       +SunStatus
       +sunrpcpack(uchar *a, uchar *ea, uchar **pa, SunRpc *rpc)
       +{
       +        u32int x;
       +
       +        if(sunuint32pack(a, ea, &a, &rpc->xid) < 0)
       +                goto Err;
       +        if(rpc->iscall){
       +                if(sunuint32pack(a, ea, &a, (x=MsgCall, &x)) < 0
       +                || sunuint32pack(a, ea, &a, (x=RpcVersion, &x)) < 0
       +                || sunuint32pack(a, ea, &a, &rpc->prog) < 0
       +                || sunuint32pack(a, ea, &a, &rpc->vers) < 0
       +                || sunuint32pack(a, ea, &a, &rpc->proc) < 0
       +                || sunauthinfopack(a, ea, &a, &rpc->cred) < 0
       +                || sunauthinfopack(a, ea, &a, &rpc->verf) < 0
       +                || sunfixedopaquepack(a, ea, &a, rpc->data, rpc->ndata) < 0)
       +                        goto Err;
       +        }else{
       +                if(sunuint32pack(a, ea, &a, (x=MsgReply, &x)) < 0)
       +                        goto Err;
       +                switch(rpc->status&0xF0000){
       +                case 0:
       +                case SunAcceptError:
       +                        if(sunuint32pack(a, ea, &a, (x=MsgAccepted, &x)) < 0
       +                        || sunauthinfopack(a, ea, &a, &rpc->verf) < 0)
       +                                goto Err;
       +                        break;
       +                default:
       +                        if(sunuint32pack(a, ea, &a, (x=MsgDenied, &x)) < 0)
       +                                goto Err;
       +                        break;
       +                }
       +
       +                switch(rpc->status){
       +                case SunSuccess:
       +                        if(sunuint32pack(a, ea, &a, (x=MsgSuccess, &x)) < 0
       +                        || sunfixedopaquepack(a, ea, &a, rpc->data, rpc->ndata) < 0)
       +                                goto Err;
       +                        break;
       +                case SunRpcMismatch:
       +                case SunProgMismatch:
       +                        if(sunuint32pack(a, ea, &a, (x=rpc->status&0xFFFF, &x)) < 0
       +                        || sunuint32pack(a, ea, &a, &rpc->low) < 0
       +                        || sunuint32pack(a, ea, &a, &rpc->high) < 0)
       +                                goto Err;
       +                        break;
       +                default:
       +                        if(sunuint32pack(a, ea, &a, (x=rpc->status&0xFFFF, &x)) < 0)
       +                                goto Err;
       +                        break;
       +                }
       +        }
       +        *pa = a;
       +        return SunSuccess;
       +
       +Err:
       +        *pa = ea;
       +        return SunGarbageArgs;
       +}
       +
       +uint
       +sunrpcsize(SunRpc *rpc)
       +{
       +        uint a;
       +
       +        a = 4;
       +        if(rpc->iscall){
       +                a += 5*4;
       +                a += sunauthinfosize(&rpc->cred);
       +                a += sunauthinfosize(&rpc->verf);
       +                a += sunfixedopaquesize(rpc->ndata);
       +        }else{
       +                a += 4;
       +                switch(rpc->status&0xF0000){
       +                case 0:
       +                case SunAcceptError:
       +                        a += 4+sunauthinfosize(&rpc->verf);
       +                        break;
       +                default:
       +                        a += 4;
       +                        break;
       +                }
       +
       +                switch(rpc->status){
       +                case SunSuccess:
       +                        a += 4+sunfixedopaquesize(rpc->ndata);
       +                        break;
       +                case SunRpcMismatch:
       +                case SunProgMismatch:
       +                        a += 3*4;
       +                default:
       +                        a += 4;
       +                }
       +        }
       +        return a;
       +}
       +
       +SunStatus
       +sunrpcunpack(uchar *a, uchar *ea, uchar **pa, SunRpc *rpc)
       +{
       +        u32int x;
       +
       +        memset(rpc, 0, sizeof *rpc);
       +        if(sunuint32unpack(a, ea, &a, &rpc->xid) < 0
       +        || sunuint32unpack(a, ea, &a, &x) < 0)
       +                goto Err;
       +
       +        switch(x){
       +        default:
       +                goto Err;
       +        case MsgCall:
       +                rpc->iscall = 1;
       +                if(sunuint32unpack(a, ea, &a, &x) < 0 || x != RpcVersion
       +                || sunuint32unpack(a, ea, &a, &rpc->prog) < 0
       +                || sunuint32unpack(a, ea, &a, &rpc->vers) < 0
       +                || sunuint32unpack(a, ea, &a, &rpc->proc) < 0
       +                || sunauthinfounpack(a, ea, &a, &rpc->cred) < 0
       +                || sunauthinfounpack(a, ea, &a, &rpc->verf) < 0)
       +                        goto Err;
       +                rpc->ndata = ea-a;
       +                rpc->data = a;
       +                a = ea;
       +                break;
       +
       +        case MsgReply:
       +                rpc->iscall = 0;
       +                if(sunuint32unpack(a, ea, &a, &x) < 0)
       +                        goto Err;
       +                switch(x){
       +                default:
       +                        goto Err;
       +                case MsgAccepted:
       +                        if(sunauthinfounpack(a, ea, &a, &rpc->verf) < 0
       +                        || sunuint32unpack(a, ea, &a, &x) < 0)
       +                                goto Err;
       +                        switch(x){
       +                        case MsgSuccess:
       +                                rpc->status = SunSuccess;
       +                                rpc->ndata = ea-a;
       +                                rpc->data = a;
       +                                a = ea;
       +                                break;
       +                        case MsgProgUnavail:
       +                        case MsgProcUnavail:
       +                        case MsgGarbageArgs:
       +                        case MsgSystemErr:
       +                                rpc->status = SunAcceptError | x;
       +                                break;
       +                        case MsgProgMismatch:
       +                                rpc->status = SunAcceptError | x;
       +                                if(sunuint32unpack(a, ea, &a, &rpc->low) < 0
       +                                || sunuint32unpack(a, ea, &a, &rpc->high) < 0)
       +                                        goto Err;
       +                                break;
       +                        }
       +                        break;
       +                case MsgDenied:
       +                        if(sunuint32unpack(a, ea, &a, &x) < 0)
       +                                goto Err;
       +                        switch(x){
       +                        default:
       +                                goto Err;
       +                        case MsgAuthError:
       +                                if(sunuint32unpack(a, ea, &a, &x) < 0)
       +                                        goto Err;
       +                                rpc->status = SunAuthError | x;
       +                                break;
       +                        case MsgRpcMismatch:
       +                                rpc->status = SunRejectError | x;
       +                                if(sunuint32unpack(a, ea, &a, &rpc->low) < 0
       +                                || sunuint32unpack(a, ea, &a, &rpc->high) < 0)
       +                                        goto Err;
       +                                break;
       +                        }
       +                        break;
       +                }
       +        }
       +        *pa = a;
       +        return SunSuccess;
       +
       +Err:
       +        *pa = ea;
       +        return SunGarbageArgs;
       +}
       +
       +void
       +sunrpcprint(Fmt *fmt, SunRpc *rpc)
       +{
       +        fmtprint(fmt, "xid=%#ux", rpc->xid);
       +        if(rpc->iscall){
       +                fmtprint(fmt, " prog %#ux vers %#ux proc %#ux [", rpc->prog, rpc->vers, rpc->proc);
       +                sunauthinfoprint(fmt, &rpc->cred);
       +                fmtprint(fmt, "] [");
       +                sunauthinfoprint(fmt, &rpc->verf);
       +                fmtprint(fmt, "]");
       +        }else{
       +                fmtprint(fmt, " status %#ux [", rpc->status);
       +                sunauthinfoprint(fmt, &rpc->verf);
       +                fmtprint(fmt, "] low %#ux high %#ux", rpc->low, rpc->high);
       +        }
       +}
       +
       +void
       +sunauthinfoprint(Fmt *fmt, SunAuthInfo *ai)
       +{
       +        switch(ai->flavor){
       +        case SunAuthNone:
       +                fmtprint(fmt, "none");
       +                break;
       +        case SunAuthShort:
       +                fmtprint(fmt, "short");
       +                break;
       +        case SunAuthSys:
       +                fmtprint(fmt, "sys");
       +                break;
       +        default:
       +                fmtprint(fmt, "%#ux", ai->flavor);
       +                break;
       +        }
       +//        if(ai->ndata)
       +//                fmtprint(fmt, " %.*H", ai->ndata, ai->data);
       +}
       +
       +uint
       +sunauthinfosize(SunAuthInfo *ai)
       +{
       +        return 4 + sunvaropaquesize(ai->ndata);
       +}
       +
       +int
       +sunauthinfopack(uchar *a, uchar *ea, uchar **pa, SunAuthInfo *ai)
       +{
       +        if(sunuint32pack(a, ea, &a, &ai->flavor) < 0
       +        || sunvaropaquepack(a, ea, &a, &ai->data, &ai->ndata, 400) < 0)
       +                goto Err;
       +        *pa = a;
       +        return 0;
       +
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +
       +int
       +sunauthinfounpack(uchar *a, uchar *ea, uchar **pa, SunAuthInfo *ai)
       +{
       +        if(sunuint32unpack(a, ea, &a, &ai->flavor) < 0
       +        || sunvaropaqueunpack(a, ea, &a, &ai->data, &ai->ndata, 400) < 0)
       +                goto Err;
       +        *pa = a;
       +        return 0;
       +
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +
       +int
       +sunenumpack(uchar *a, uchar *ea, uchar **pa, int *e)
       +{
       +        u32int x;
       +
       +        x = *e;
       +        return sunuint32pack(a, ea, pa, &x);
       +}
       +
       +int
       +sunuint1pack(uchar *a, uchar *ea, uchar **pa, u1int *u)
       +{
       +        u32int x;
       +
       +        x = *u;
       +        return sunuint32pack(a, ea, pa, &x);
       +}
       +
       +int
       +sunuint32pack(uchar *a, uchar *ea, uchar **pa, u32int *u)
       +{
       +        u32int x;
       +
       +        if(ea-a < 4)
       +                goto Err;
       +
       +        x = *u;
       +        *a++ = x>>24;
       +        *a++ = x>>16;
       +        *a++ = x>>8;
       +        *a++ = x;
       +        *pa = a;
       +        return 0;
       +
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +
       +int
       +sunenumunpack(uchar *a, uchar *ea, uchar **pa, int *e)
       +{
       +        u32int x;
       +        if(sunuint32unpack(a, ea, pa, &x) < 0)
       +                return -1;
       +        *e = x;
       +        return 0;
       +}
       +
       +int
       +sunuint1unpack(uchar *a, uchar *ea, uchar **pa, u1int *u)
       +{
       +        u32int x;
       +        if(sunuint32unpack(a, ea, pa, &x) < 0 || (x!=0 && x!=1)){
       +                *pa = ea;
       +                return -1;
       +        }
       +        *u = x;
       +        return 0;
       +}
       +
       +int
       +sunuint32unpack(uchar *a, uchar *ea, uchar **pa, u32int *u)
       +{
       +        u32int x;
       +
       +        if(ea-a < 4)
       +                goto Err;
       +        x = *a++ << 24;
       +        x |= *a++ << 16;
       +        x |= *a++ << 8;
       +        x |= *a++;
       +        *pa = a;
       +        *u = x;
       +        return 0;
       +
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +
       +int
       +sunuint64unpack(uchar *a, uchar *ea, uchar **pa, u64int *u)
       +{
       +        u32int x, y;
       +
       +        if(sunuint32unpack(a, ea, &a, &x) < 0
       +        || sunuint32unpack(a, ea, &a, &y) < 0)
       +                goto Err;
       +        *u = ((uvlong)x<<32) | y;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +
       +int
       +sunuint64pack(uchar *a, uchar *ea, uchar **pa, u64int *u)
       +{
       +        u32int x, y;
       +
       +        x = *u >> 32;
       +        y = *u;
       +        if(sunuint32pack(a, ea, &a, &x) < 0
       +        || sunuint32pack(a, ea, &a, &y) < 0)
       +                goto Err;
       +        *pa = a;
       +        return 0;
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +
       +uint
       +sunstringsize(char *s)
       +{
       +        return (4+strlen(s)+3) & ~3;
       +}
       +
       +int
       +sunstringunpack(uchar *a, uchar *ea, uchar **pa, char **s, u32int max)
       +{
       +        uchar *dat;
       +        u32int n;
       +
       +        if(sunvaropaqueunpack(a, ea, pa, &dat, &n, max) < 0)
       +                goto Err;
       +        /* slide string down over length to make room for NUL */
       +        memmove(dat-1, dat, n);
       +        dat[-1+n] = 0;
       +        *s = (char*)(dat-1);
       +        return 0;
       +Err:
       +        return -1;
       +}
       +
       +int
       +sunstringpack(uchar *a, uchar *ea, uchar **pa, char **s, u32int max)
       +{
       +        u32int n;
       +
       +        n = strlen(*s);
       +        return sunvaropaquepack(a, ea, pa, (uchar**)s, &n, max);
       +}
       +
       +uint
       +sunvaropaquesize(u32int n)
       +{
       +        return (4+n+3) & ~3;
       +}
       +
       +int
       +sunvaropaquepack(uchar *a, uchar *ea, uchar **pa, uchar **dat, u32int *ndat, u32int max)
       +{
       +        if(*ndat > max || sunuint32pack(a, ea, &a, ndat) < 0
       +        || sunfixedopaquepack(a, ea, &a, *dat, *ndat) < 0)
       +                goto Err;
       +        *pa = a;
       +        return 0;
       +
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +
       +int
       +sunvaropaqueunpack(uchar *a, uchar *ea, uchar **pa, uchar **dat, u32int *ndat, u32int max)
       +{
       +        if(sunuint32unpack(a, ea, &a, ndat) < 0
       +        || *ndat > max)
       +                goto Err;
       +        *dat = a;
       +        a += (*ndat+3)&~3;
       +        if(a > ea)
       +                goto Err;
       +        *pa = a;
       +        return 0;
       +
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +
       +uint
       +sunfixedopaquesize(u32int n)
       +{
       +        return (n+3) & ~3;
       +}
       +
       +int
       +sunfixedopaquepack(uchar *a, uchar *ea, uchar **pa, uchar *dat, u32int n)
       +{
       +        uint nn;
       +
       +        nn = (n+3)&~3;
       +        if(a+nn > ea)
       +                goto Err;
       +        memmove(a, dat, n);
       +        if(nn > n)
       +                memset(a+n, 0, nn-n);
       +        a += nn;
       +        *pa = a;
       +        return 0;
       +
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +
       +int
       +sunfixedopaqueunpack(uchar *a, uchar *ea, uchar **pa, uchar *dat, u32int n)
       +{
       +        uint nn;
       +
       +        nn = (n+3)&~3;
       +        if(a+nn > ea)
       +                goto Err;
       +        memmove(dat, a, n);
       +        a += nn;
       +        *pa = a;
       +        return 0;
       +
       +Err:
       +        *pa = ea;
       +        return -1;
       +}
       +
 (DIR) diff --git a/src/libsunrpc/server.c b/src/libsunrpc/server.c
       t@@ -0,0 +1,277 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <thread.h>
       +#include <sunrpc.h>
       +
       +/*
       + * Sun RPC server; for now, no reply cache
       + */
       +
       +static void sunrpcproc(void*);
       +static void sunrpcrequestthread(void*);
       +static void sunrpcreplythread(void*);
       +static void sunrpcforkthread(void*);
       +static SunProg *sunfindprog(SunSrv*, SunMsg*, SunRpc*, Channel**);
       +
       +typedef struct Targ Targ;
       +struct Targ
       +{
       +        void (*fn)(void*);
       +        void *arg;
       +};
       +
       +SunSrv*
       +sunsrv(void)
       +{
       +        SunSrv *srv;
       +
       +        srv = emalloc(sizeof(SunSrv));
       +        srv->chatty = 0;
       +        srv->crequest = chancreate(sizeof(SunMsg*), 16);
       +        srv->creply = chancreate(sizeof(SunMsg*), 16);
       +        srv->cthread = chancreate(sizeof(Targ), 4);
       +
       +        proccreate(sunrpcproc, srv, SunStackSize);
       +        return srv;
       +}
       +
       +void
       +sunsrvprog(SunSrv *srv, SunProg *prog, Channel *c)
       +{
       +        if(srv->nprog%16 == 0){
       +                srv->prog = erealloc(srv->prog, (srv->nprog+16)*sizeof(srv->prog[0]));
       +                srv->cdispatch = erealloc(srv->cdispatch, (srv->nprog+16)*sizeof(srv->cdispatch[0]));
       +        }
       +        srv->prog[srv->nprog] = prog;
       +        srv->cdispatch[srv->nprog] = c;
       +        srv->nprog++;
       +}
       +
       +static void
       +sunrpcproc(void *v)
       +{
       +        threadcreate(sunrpcreplythread, v, SunStackSize);
       +        threadcreate(sunrpcrequestthread, v, SunStackSize);
       +        threadcreate(sunrpcforkthread, v, SunStackSize);
       +
       +}
       +
       +static void
       +sunrpcforkthread(void *v)
       +{
       +        SunSrv *srv = v;
       +        Targ t;
       +
       +        while(recv(srv->cthread, &t) == 1)
       +                threadcreate(t.fn, t.arg, SunStackSize);
       +}
       +
       +void
       +sunsrvthreadcreate(SunSrv *srv, void (*fn)(void*), void *arg)
       +{
       +        Targ t;
       +
       +        t.fn = fn;
       +        t.arg = arg;
       +        send(srv->cthread, &t);
       +}
       +
       +static void
       +sunrpcrequestthread(void *v)
       +{
       +        uchar *p, *ep;
       +        Channel *c;
       +        SunSrv *srv = v;
       +        SunMsg *m;
       +        SunProg *pg;
       +        SunStatus ok;
       +
       +        while((m = recvp(srv->crequest)) != nil){
       +                /* could look up in cache here? */
       +
       +if(srv->chatty) fprint(2, "sun msg %p count %d\n", m, m->count);
       +                m->srv = srv;
       +                p = m->data;
       +                ep = p+m->count;
       +                if(sunrpcunpack(p, ep, &p, &m->rpc) != SunSuccess){
       +                        fprint(2, "in: %.*H unpack failed\n", m->count, m->data);
       +                        sunmsgdrop(m);
       +                        continue;
       +                }
       +                if(srv->chatty)
       +                        fprint(2, "in: %B\n", &m->rpc);
       +
       +                if(srv->alwaysreject){
       +                        if(srv->chatty)
       +                                fprint(2, "\trejecting\n");
       +                        sunmsgreplyerror(m, SunAuthTooWeak);
       +                        continue;
       +                }
       +
       +                if(!m->rpc.iscall){
       +                        sunmsgreplyerror(m, SunGarbageArgs);
       +                        continue;
       +                }
       +
       +                if((pg = sunfindprog(srv, m, &m->rpc, &c)) == nil){
       +                        /* sunfindprog sent error */
       +                        continue;
       +                }
       +
       +                p = m->rpc.data;
       +                ep = p+m->rpc.ndata;
       +                m->call = nil;
       +                if((ok = suncallunpackalloc(pg, m->rpc.proc<<1, p, ep, &p, &m->call)) != SunSuccess){
       +                        sunmsgreplyerror(m, ok);
       +                        continue;
       +                }
       +                m->call->rpc = m->rpc;
       +
       +                if(srv->chatty)
       +                        fprint(2, "\t%C\n", m->call);
       +
       +                m->pg = pg;
       +                sendp(c, m);
       +        }
       +}
       +
       +static SunProg*
       +sunfindprog(SunSrv *srv, SunMsg *m, SunRpc *rpc, Channel **pc)
       +{
       +        int i, vlo, vhi;
       +        SunProg *pg;
       +
       +        vlo = 0x7fffffff;
       +        vhi = -1;
       +
       +        for(i=0; i<srv->nprog; i++){
       +                pg = srv->prog[i];
       +                if(pg->prog != rpc->prog)
       +                        continue;
       +                if(pg->vers == rpc->vers){
       +                        *pc = srv->cdispatch[i];
       +                        return pg;
       +                }
       +                /* right program, wrong version: record range */
       +                if(pg->vers < vlo)
       +                        vlo = pg->vers;
       +                if(pg->vers > vhi)
       +                        vhi = pg->vers;
       +        }
       +        if(vhi == -1){
       +                if(srv->chatty)
       +                        fprint(2, "\tprogram %ud unavailable\n", rpc->prog);
       +                sunmsgreplyerror(m, SunProgUnavail);
       +        }else{
       +                /* putting these in rpc is a botch */
       +                rpc->low = vlo;
       +                rpc->high = vhi;
       +                if(srv->chatty)
       +                        fprint(2, "\tversion %ud unavailable; have %d-%d\n", rpc->vers, vlo, vhi);
       +                sunmsgreplyerror(m, SunProgMismatch);
       +        }
       +        return nil;
       +}
       +
       +static void
       +sunrpcreplythread(void *v)
       +{
       +        SunMsg *m;
       +        SunSrv *srv = v;
       +
       +        while((m = recvp(srv->creply)) != nil){
       +                /* could record in cache here? */
       +                sendp(m->creply, m);
       +        }        
       +}
       +
       +int
       +sunmsgreplyerror(SunMsg *m, SunStatus error)
       +{
       +        uchar *p, *bp, *ep;
       +        int n;
       +
       +        m->rpc.status = error;
       +        m->rpc.iscall = 0;
       +        m->rpc.verf.flavor = SunAuthNone;
       +        m->rpc.data = nil;
       +        m->rpc.ndata = 0;
       +
       +        if(m->srv->chatty)
       +                fprint(2, "out: %B\n", &m->rpc);
       +
       +        n = sunrpcsize(&m->rpc);
       +        bp = emalloc(n);
       +        ep = bp+n;
       +        p = bp;
       +        if(sunrpcpack(p, ep, &p, &m->rpc) < 0){
       +                fprint(2, "sunrpcpack failed\n");
       +                sunmsgdrop(m);
       +                return 0;
       +        }
       +        if(p != ep){
       +                fprint(2, "sunmsgreplyerror: rpc sizes didn't work out\n");
       +                sunmsgdrop(m);
       +                return 0;
       +        }
       +        free(m->data);
       +        m->data = bp;
       +        m->count = n;
       +        sendp(m->srv->creply, m);
       +        return 0;
       +}
       +
       +int
       +sunmsgreply(SunMsg *m, SunCall *c)
       +{
       +        int n1, n2;
       +        uchar *bp, *p, *ep;
       +
       +        c->type = m->call->type+1;
       +        c->rpc.iscall = 0;
       +        c->rpc.prog = m->rpc.prog;
       +        c->rpc.vers = m->rpc.vers;
       +        c->rpc.proc = m->rpc.proc;
       +        c->rpc.xid = m->rpc.xid;
       +
       +        if(m->srv->chatty){
       +                fprint(2, "out: %B\n", &c->rpc);
       +                fprint(2, "\t%C\n", c);
       +        }
       +
       +        n1 = sunrpcsize(&c->rpc);
       +        n2 = suncallsize(m->pg, c);
       +
       +        bp = emalloc(n1+n2);
       +        ep = bp+n1+n2;
       +        p = bp;
       +        if(sunrpcpack(p, ep, &p, &c->rpc) != SunSuccess){
       +                fprint(2, "sunrpcpack failed\n");
       +                return sunmsgdrop(m);
       +        }
       +        if(suncallpack(m->pg, p, ep, &p, c) != SunSuccess){
       +                fprint(2, "pg->pack failed\n");
       +                return sunmsgdrop(m);
       +        }
       +        if(p != ep){
       +                fprint(2, "sunmsgreply: sizes didn't work out\n");
       +                return sunmsgdrop(m);
       +        }
       +        free(m->data);
       +        m->data = bp;
       +        m->count = n1+n2;
       +
       +        sendp(m->srv->creply, m);
       +        return 0;
       +}
       +
       +int
       +sunmsgdrop(SunMsg *m)
       +{
       +        free(m->data);
       +        free(m->call);
       +        memset(m, 0xFB, sizeof *m);
       +        free(m);
       +        return 0;
       +}
       +
 (DIR) diff --git a/src/libsunrpc/suncall.c b/src/libsunrpc/suncall.c
       t@@ -0,0 +1,14 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <thread.h>
       +#include <sunrpc.h>
       +
       +void
       +suncallsetup(SunCall *c, SunProg *prog, uint proc)
       +{
       +        c->rpc.prog = prog->prog;
       +        c->rpc.vers = prog->vers;
       +        c->rpc.proc = proc>>1;
       +        c->rpc.iscall = !(proc&1);
       +        c->type = proc;
       +}
 (DIR) diff --git a/src/libsunrpc/udp.c b/src/libsunrpc/udp.c
       t@@ -0,0 +1,120 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <ip.h>
       +#include <thread.h>
       +#include <sunrpc.h>
       +
       +typedef struct SunMsgUdp SunMsgUdp;
       +struct SunMsgUdp
       +{
       +        SunMsg msg;
       +        Udphdr udp;
       +};
       +
       +typedef struct Arg Arg;
       +struct Arg
       +{
       +        SunSrv *srv;
       +        Channel *creply;
       +        Channel *csync;
       +        int fd;
       +};
       +
       +enum
       +{
       +        UdpMaxRead = 65536+Udphdrsize
       +};
       +static void
       +sunudpread(void *v)
       +{
       +        int n, paraport, port;
       +        uchar *buf;
       +        Arg arg = *(Arg*)v;
       +        SunMsgUdp *msg;
       +        SunSrv *srv;
       +        Udphdr udp;
       +        uchar localip[IPaddrlen];
       +
       +        sendp(arg.csync, 0);
       +        srv = arg.srv;
       +        paraport = -1;
       +
       +        /* 127.1 */
       +        memmove(localip, v4prefix, IPaddrlen);
       +        localip[12] = 127;
       +        localip[15] = 1;
       +
       +        buf = emalloc(UdpMaxRead);
       +        while((n = udpread(arg.fd, &udp, buf, UdpMaxRead)) > 0){
       +                if(arg.srv->chatty)
       +                        fprint(2, "udpread got %d (%d) from %I\n", n, Udphdrsize, udp.raddr);
       +                if((srv->localonly || srv->localparanoia) && ipcmp(udp.raddr, localip) != 0){
       +                        fprint(2, "dropping message from %I: not local\n", udp.raddr);
       +                        continue;
       +                }
       +                if(srv->localparanoia){
       +                        port = nhgets(udp.rport);
       +                        if(paraport == -1){
       +                                fprint(2, "paranoid mode: only %I/%d allowed\n", localip, port);
       +                                paraport = port;
       +                        }else if(paraport != port){
       +                                fprint(2, "dropping message from %I: not port %d\n", udp.raddr, port);
       +                                continue;
       +                        }
       +                }
       +                msg = emalloc(sizeof(SunMsgUdp));
       +                msg->udp = udp;
       +                msg->msg.data = emalloc(n);
       +                msg->msg.count = n;
       +                memmove(msg->msg.data, buf, n);
       +                msg->msg.creply = arg.creply;
       +                if(arg.srv->chatty)
       +                        fprint(2, "message %p count %d\n", msg, msg->msg.count);
       +                sendp(arg.srv->crequest, msg);
       +        }
       +}
       +
       +static void
       +sunudpwrite(void *v)
       +{
       +        uchar *buf;
       +        Arg arg = *(Arg*)v;
       +        SunMsgUdp *msg;
       +
       +        sendp(arg.csync, 0);
       +
       +        buf = emalloc(UdpMaxRead);
       +        while((msg = recvp(arg.creply)) != nil){
       +                if(udpwrite(arg.fd, &msg->udp, msg->msg.data, msg->msg.count) != msg->msg.count)
       +                        fprint(2, "udpwrite: %r\n");
       +                free(msg->msg.data);
       +                free(msg);
       +        }
       +}
       +
       +int
       +sunsrvudp(SunSrv *srv, char *address)
       +{
       +        int fd;
       +        char adir[40];
       +        Arg *arg;
       +
       +        fd = announce(address, adir);
       +        if(fd < 0)
       +                return -1;
       +
       +        arg = emalloc(sizeof(Arg));
       +        arg->fd = fd;
       +        arg->srv = srv;
       +        arg->creply = chancreate(sizeof(SunMsg*), 10);
       +        arg->csync = chancreate(sizeof(void*), 10);
       +
       +        proccreate(sunudpread, arg, SunStackSize);
       +        proccreate(sunudpwrite, arg, SunStackSize);
       +        recvp(arg->csync);
       +        recvp(arg->csync);
       +        chanfree(arg->csync);
       +        free(arg);
       +
       +        return 0;
       +}