/* * Yet more code duplicated to perform the amount op. */#include <u.h>#include <libc.h>#include <fcall.h>#include <thread.h>#include <auth.h>#include <ip.h>#include "names.h"#include "vols.h" static intagetfrep(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 longfswrite(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 longfsread(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 longfsclose(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 intfsattach(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 intauthfsfd(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 intfsversion(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 intdialfs(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;} intamountfs(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;}
/*
* Yet more code duplicated to perform the amount op.
*/
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
#include <auth.h>
#include <ip.h>
#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;
}