Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include "all.h"

/*
 *      Cf. /lib/rfc/rfc1094
 */

static int      mntnull(int, Rpccall*, Rpccall*);
static int      mntmnt(int, Rpccall*, Rpccall*);
static int      mntdump(int, Rpccall*, Rpccall*);
static int      mntumnt(int, Rpccall*, Rpccall*);
static int      mntumntall(int, Rpccall*, Rpccall*);
static int      mntexport(int, Rpccall*, Rpccall*);

Procmap mntproc[] = {
        0, mntnull,
        1, mntmnt,
        2, mntdump,
        3, mntumnt,
        4, mntumntall,
        5, mntexport,
        0, 0
};

long            starttime;
static int      noauth;
char *          config;
Session *       head;
Session *       tail;
int staletime = 10*60;

void
mnttimer(long now)
{
        Session *s;

        for(s=head; s; s=s->next)
                fidtimer(s, now);
}

static void
usage(void)
{
        sysfatal("usage: %s %s [-ns] [-a dialstring] [-c uidmap] [-f srvfile] "
                "[-T staletime]", argv0, commonopts);
}

void
mntinit(int argc, char **argv)
{
        int tries;

        config = "config";
        starttime = time(0);
        clog("nfs mount server init, starttime = %lud\n", starttime);
        tries = 0;
        ARGBEGIN{
        case 'a':
                ++tries;
                srvinit(-1, 0, EARGF(usage()));
                break;
        case 'c':
                config = EARGF(usage());
                break;
        case 'f':
                ++tries;
                srvinit(-1, EARGF(usage()), 0);
                break;
        case 'n':
                ++noauth;
                break;
        case 's':
                ++tries;
                srvinit(1, 0, 0);
                break;
        case 'T':
                staletime = atoi(EARGF(usage()));
                break;
        default:
                if(argopt(ARGC()) < 0)
                        sysfatal("usage: %s %s [-ns] [-a dialstring] "
                                "[-c uidmap] [-f srvfile] [-T staletime]",
                                argv0, commonopts);
                break;
        }ARGEND
noauth=1;       /* ZZZ */
        if(tries == 0 && head == 0)
                srvinit(-1, 0, "tcp!fs");
        if(head == 0)
                panic("can't initialize services");
        readunixidmaps(config);
}

void
srvinit(int fd, char *file, char *addr)
{
        char fdservice[16], *naddr;
        Session *s;
        Xfile *xp;
        Xfid *xf;
        Fid *f;

        s = calloc(1, sizeof(Session));
        s->spec = "";
        s->fd = -1;
        if(fd >= 0){
                s->fd = fd;
                sprint(fdservice, "/fd/%d", s->fd);
                s->service = strstore(fdservice);
                chat("fd = %d\n", s->fd);
        }else if(file){
                chat("file = \"%s\"\n", file);
                s->service = file;
                s->fd = open(file, ORDWR);
                if(s->fd < 0){
                        clog("can't open %s: %r\n", file);
                        goto error;
                }
        }else if(addr){
                chat("addr = \"%s\"\n", addr);
                naddr = netmkaddr(addr, 0, "9fs");
                s->service = addr;
                s->fd = dial(naddr, 0, 0, 0);
                if(s->fd < 0){
                        clog("can't dial %s: %r\n", naddr);
                        goto error;
                }
        }

        chat("version...");
        s->tag = NOTAG-1;
        s->f.msize = Maxfdata+IOHDRSZ;
        s->f.version = "9P2000";
        xmesg(s, Tversion);
        messagesize = IOHDRSZ+s->f.msize;
        chat("version spec %s size %d\n", s->f.version, s->f.msize);

        s->tag = 0;

        chat("authenticate...");
        if(authhostowner(s) < 0){
                clog("auth failed %r\n");
                goto error;
        }

        chat("attach as none...");
        f = newfid(s);
        s->f.fid = f - s->fids;
        s->f.afid = ~0x0UL;
        s->f.uname = "none";
        s->f.aname = s->spec;
        if(xmesg(s, Tattach)){
                clog("attach failed\n");
                goto error;
        }

        xp = xfile(&s->f.qid, s, 1);
        s->root = xp;
        xp->parent = xp;
        xp->name = "/";
        xf = xfid("none", xp, 1);
        xf->urfid = f;
        clog("service=%s uid=%s fid=%ld\n",
                s->service, xf->uid, xf->urfid - s->fids);
        if(tail)
                tail->next = s;
        else
                head = s;
        tail = s;
        return;

error:
        if(s->fd >= 0)
                close(s->fd);
        free(s);
}

static int
mntnull(int n, Rpccall *cmd, Rpccall *reply)
{
        USED(n, cmd, reply);
        chat("mntnull\n");
        return 0;
}

static char*
Str2str(String s, char *buf, int nbuf)
{
        int i;
        i = s.n;
        if(i >= nbuf)
                i = nbuf-1;
        memmove(buf, s.s, i);
        buf[i] = 0;
        return buf;
}

static int
mntmnt(int n, Rpccall *cmd, Rpccall *reply)
{
        int i;
        char dom[64];
        uchar *argptr = cmd->args;
        uchar *dataptr = reply->results;
        Authunix au;
        Xfile *xp;
        String root;

        chat("mntmnt...\n");
        if(n < 8)
                return garbage(reply, "n too small");
        argptr += string2S(argptr, &root);
        if(argptr != &((uchar *)cmd->args)[n])
                return garbage(reply, "bad count");
        clog("host=%I, port=%ld, root=\"%.*s\"...",
                cmd->host, cmd->port, utfnlen(root.s, root.n), root.s);
        if(auth2unix(&cmd->cred, &au) != 0){
                chat("auth flavor=%ld, count=%ld\n",
                        cmd->cred.flavor, cmd->cred.count);
                for(i=0; i<cmd->cred.count; i++)
                        chat(" %.2ux", ((uchar *)cmd->cred.data)[i]);
                chat("\n");
                clog("auth: bad credentials");
                return error(reply, 1);
        }
        clog("auth: %ld %.*s u=%ld g=%ld",
                au.stamp, utfnlen(au.mach.s, au.mach.n), au.mach.s, au.uid, au.gid);
        for(i=0; i<au.gidlen; i++)
                chat(", %ld", au.gids[i]);
        chat("...");
        if(getdom(cmd->host, dom, sizeof(dom))<0){
                clog("auth: unknown ip address");
                return error(reply, 1);
        }
        chat("dom=%s...", dom);
        xp = xfroot(root.s, root.n);
        if(xp == 0){
                chat("xp=0...");
                clog("mntmnt: no fs");
                return error(reply, 3);
        }

        PLONG(0);
        dataptr += xp2fhandle(xp, dataptr);
        chat("OK\n");
        return dataptr - (uchar *)reply->results;
}

static int
mntdump(int n, Rpccall *cmd, Rpccall *reply)
{
        if(n != 0)
                return garbage(reply, "mntdump");
        USED(cmd);
        chat("mntdump...");
        return error(reply, FALSE);
}

static int
mntumnt(int n, Rpccall *cmd, Rpccall *reply)
{
        if(n <= 0)
                return garbage(reply, "mntumnt");
        USED(cmd);
        chat("mntumnt\n");
        return 0;
}

static int
mntumntall(int n, Rpccall *cmd, Rpccall *reply)
{
        if(n != 0)
                return garbage(reply, "mntumntall");
        USED(cmd);
        chat("mntumntall\n");
        return 0;
}

static int
mntexport(int n, Rpccall *cmd, Rpccall *reply)
{
        uchar *dataptr = reply->results;
        Authunix au;
        int i;

        chat("mntexport...");
        if(n != 0)
                return garbage(reply, "mntexport");
        if(auth2unix(&cmd->cred, &au) != 0){
                chat("auth flavor=%ld, count=%ld\n",
                        cmd->cred.flavor, cmd->cred.count);
                for(i=0; i<cmd->cred.count; i++)
                        chat(" %.2ux", ((uchar *)cmd->cred.data)[i]);
                chat("...");
                au.mach.n = 0;
        }else
                chat("%ld@%.*s...", au.uid, utfnlen(au.mach.s, au.mach.n), au.mach.s);
        PLONG(TRUE);
        PLONG(1);
        PPTR("/", 1);
        if(au.mach.n > 0){
                PLONG(TRUE);
                PLONG(au.mach.n);
                PPTR(au.mach.s, au.mach.n);
        }
        PLONG(FALSE);
        PLONG(FALSE);
        chat("OK\n");
        return dataptr - (uchar *)reply->results;
}

Xfile *
xfroot(char *name, int n)
{
        Session *s;
        char *p;

        if(n <= 0)
                n = strlen(name);
        chat("xfroot: %.*s...", utfnlen(name, n), name);
        if(n == 1 && name[0] == '/')
                return head->root;
        for(s=head; s; s=s->next){
                if(strncmp(name, s->service, n) == 0)
                        return s->root;
                p = strrchr(s->service, '!');   /* for -a tcp!foo */
                if(p && strncmp(name, p+1, n) == 0)
                        return s->root;
                p = strrchr(s->service, '/');   /* for -f /srv/foo */
                if(p && strncmp(name, p+1, n) == 0)
                        return s->root;
        }
        return 0;
}