/* * Yet more code duplicated to perform the amount op. */ #include #include #include #include #include #include #include "names.h" #include "vols.h" static int agetfrep(int fd, Frpc* fop) { int r; r = getfrep(fd, fop); if (r > 0 || r == -1) Dbgprint(fop->fid, " <= %F\n", &fop->r); return r; } static long fswrite(int fd, int fid, Frpc* fop, void* a, long n) { fop->f.tag = 0xb; fop->f.type= Twrite; fop->f.fid = fid; fop->f.data = a; fop->f.count = n; if (putfcall(fd, fop) <= 0 || agetfrep(fd, fop) <= 0 || fop->r.type != Rwrite || fop->r.tag != fop->f.tag) return -1; return fop->r.count; } static long fsread(int fd, int fid, Frpc* fop, void* a, long n) { fop->f.tag = 0xc; fop->f.type= Tread; fop->f.fid = fid; fop->f.count = n; if (putfcall(fd, fop) <= 0 || agetfrep(fd, fop) <= 0 || fop->r.type != Rread || fop->r.tag != fop->f.tag) return -1; memmove(a, fop->r.data, fop->r.count); return fop->r.count; } static long fsclose(int fd, int fid, Frpc* fop) { fop->f.tag = 0xd; fop->f.type= Tclunk; fop->f.fid = fid; if (putfcall(fd, fop) <= 0 || agetfrep(fd, fop) <= 0 || fop->r.type != Rclunk || fop->r.tag != fop->f.tag) return -1; return 0; } static int fsattach(int fd, int fid, int afid, char* spec, Frpc* fop, Qid* q) { fop->f.tag = 0xe; fop->f.type= Tattach; fop->f.fid = fid; fop->f.afid= afid; fop->f.uname = getuser(); fop->f.aname = spec; if (putfcall(fd, fop) <= 0 || agetfrep(fd, fop) <= 0 || fop->r.type != Rattach || fop->r.tag != fop->f.tag) return -1; *q = fop->r.qid; return 0; } static char* anames[] = { "ok", "done", "error", "needkey", "badkey", "writenext", "toosmall", "toobig", "rpcfailure", "phase" }; static AuthInfo* fsfauth_proxy(int fsfd, int afid, Frpc* fop, AuthRpc *rpc, char* params) { char *buf; int m, n, ret; AuthInfo *a; char oerr[ERRMAX]; int id; rerrstr(oerr, sizeof oerr); werrstr("UNKNOWN AUTH ERROR"); assert(rpc); if(auth_rpc(rpc, "start", params, strlen(params)) != ARok){ werrstr("fauth_proxy start: %r"); return nil; } buf = emalloc(AuthRpcMax); for(;;){ id = auth_rpc(rpc, "read", nil, 0); switch(id){ case ARdone: free(buf); a = auth_getinfo(rpc); errstr(oerr, sizeof oerr); /* no error, restore whatever was there */ return a; case ARok: if(fswrite(fsfd, afid, fop, rpc->arg, rpc->narg) != rpc->narg){ werrstr("auth_proxy write fd: %r"); goto Error; } break; case ARphase: n = 0; memset(buf, 0, AuthRpcMax); while((ret = auth_rpc(rpc, "write", buf, n)) == ARtoosmall){ if(atoi(rpc->arg) > AuthRpcMax) break; m = fsread(fsfd, afid, fop, buf+n, atoi(rpc->arg)-n); if(m <= 0){ if(m == 0) werrstr("auth_proxy short read: %s", buf); goto Error; } n += m; } if (ret != ARok){ goto Error; } break; default: werrstr("auth_proxy rpc: %r"); goto Error; } } Error: free(buf); return nil; } static AuthInfo* fsauth_proxy(int fsfd, int afid, Frpc* fop, char* params) { AuthInfo *ai; AuthRpc *rpc; int afd; quotefmtinstall(); /* just in case */ afd = open("/mnt/factotum/rpc", ORDWR); if(afd < 0){ // Try mounting it. afd = open("#s/factotum", ORDWR); if (afd < 0){ return nil; } mount(afd, -1, "/mnt", MREPL, ""); afd = open("/mnt/factotum/rpc", ORDWR); if (afd < 0){ return nil; } } rpc = auth_allocrpc(afd); if(rpc == nil) { close(afd); return nil; } ai = fsfauth_proxy(fsfd, afid, fop, rpc, params); auth_freerpc(rpc); close(afd); return ai; } static int authfsfd(int fd, char* spec, Frpc* fop) { AuthInfo*ai; int afid; fop->f.tag = 0xb; fop->f.type= Tauth; fop->f.afid = getfidnr(); fop->f.uname = getuser(); fop->f.aname = spec; afid = -1; if (putfcall(fd, fop) <= 0 || agetfrep(fd, fop) <= 0) goto fail; if (fop->r.type == Rerror) // no auth required. goto done; if (fop->r.type != Rauth || fop->r.tag != fop->f.tag) goto fail; else afid = fop->f.afid; /* The next call depends on linking against our own * fauth_proxy function, which speaks 9P to the server * instead of using the kernel. */ ai = fsauth_proxy(fd, afid, fop, "proto=p9any role=client"); if (0 && ai == nil) // Debugging this goto fail; auth_freeAI(ai); done: return afid; fail: close(fd); return -1; } static int fsversion(int fd, Frpc* fop) { fop->f.tag = NOTAG; fop->f.type= Tversion; fop->f.msize= Maxmsglen; fop->f.version = "9P2000"; if (putfcall(fd, fop) <= 0 || agetfrep(fd, fop) <= 0){ vdprint(2, "can't RPC Tversion: %r\n"); return -1; } if (fop->r.tag != NOTAG || fop->r.type != Rversion){ vdprint(2, "bad reply for Tversion"); return -1; } if (strcmp(fop->r.version, "9P2000")){ vdprint(2, "bad server version\n"); return -1; } if (fop->r.msize < Maxmsglen) msglen = fop->r.msize; return 1; } static int dialfs(Fs* fs) { int fd, cfd; char dir[50]; char* s; cfd = -1; if (fs->addr[0] == '#' || fs->addr[0] == '/') fd = open(fs->addr, ORDWR); else { s=smprint("/net/%s", fs->addr); fd = dial(s, 0, dir, &cfd); free(s); if (cfd != -1){ fprint(cfd, "keepalive 2000\n"); close(cfd); } } return fd; } int amountfs(Fs* fs) { int fd, afid, r; Frpc* fop; int doversion; Dir* d; fd = dialfs(fs); if (fd < 0){ vdprint(2, "%s: can't dial %s: %r\n", argv0, fs->addr); return 0; } if (fs->addr[0] != '#' && fs->addr[0] != '/') doversion = 1; else { d = dirfstat(fd); if (d == nil) return 0; doversion = (d->qid.path != fs->fdqid.path); fs->fdqid = d->qid; free(d); } fop = rpcalloc(); if (doversion && fsversion(fd, fop) < 0){ vdprint(2, "%s: %s: bad fversion\n", argv0, fs->addr); close(fd); rpcfree(fop); return 0; } afid = authfsfd(fd, fs->spec, fop); if (fsattach(fd, fs->fid->snr, afid, fs->spec, fop, &fs->fid->qid) < 0){ vdprint(2, "%s: attach failed: %s\n", argv0, fs->addr); close(fd); // afid will be collected by the server. r = 0; } else { if (afid >= 0) fsclose(fd, afid, fop); fs->fid->qid.path |= fs->qid.path; fs->fd = fd; // make it official. r = 1; } rpcfree(fop); return r; }