xref: /plan9/sys/src/cmd/nfs.c (revision f314cdf7834bd43eca346fc56576f76e4a83155b)
134e04225SDavid du Colombier /* Copyright © 2003 Russ Cox, MIT; see /sys/src/libsunrpc/COPYING */
234e04225SDavid du Colombier #include <u.h>
334e04225SDavid du Colombier #include <libc.h>
434e04225SDavid du Colombier #include <bio.h>
534e04225SDavid du Colombier #include <fcall.h>
634e04225SDavid du Colombier #include <thread.h>
734e04225SDavid du Colombier #include <9p.h>
834e04225SDavid du Colombier #include <sunrpc.h>
934e04225SDavid du Colombier #include <nfs3.h>
1034e04225SDavid du Colombier 
1134e04225SDavid du Colombier SunClient *nfscli;
1234e04225SDavid du Colombier SunClient *mntcli;
1334e04225SDavid du Colombier char *defaultpath = "/";
1434e04225SDavid du Colombier Channel *fschan;
1534e04225SDavid du Colombier char *sys;
1634e04225SDavid du Colombier int verbose;
1734e04225SDavid du Colombier int readplus = 0;
1834e04225SDavid du Colombier 
1934e04225SDavid du Colombier 
2034e04225SDavid du Colombier typedef struct Auth Auth;
2134e04225SDavid du Colombier struct Auth
2234e04225SDavid du Colombier {
2334e04225SDavid du Colombier 	int ref;
2434e04225SDavid du Colombier 	uchar *data;
2534e04225SDavid du Colombier 	int ndata;
2634e04225SDavid du Colombier };
2734e04225SDavid du Colombier 
2834e04225SDavid du Colombier typedef struct FidAux FidAux;
2934e04225SDavid du Colombier struct FidAux
3034e04225SDavid du Colombier {
3134e04225SDavid du Colombier 	Nfs3Handle handle;
3234e04225SDavid du Colombier 
3334e04225SDavid du Colombier 	u64int cookie;	/* for continuing directory reads */
3434e04225SDavid du Colombier 	char *name;	/* botch: for remove and rename */
3534e04225SDavid du Colombier 	Nfs3Handle parent;	/* botch: for remove and rename */
3634e04225SDavid du Colombier 	char err[ERRMAX];	/* for walk1 */
3734e04225SDavid du Colombier 	Auth *auth;
3834e04225SDavid du Colombier };
3934e04225SDavid du Colombier 
4034e04225SDavid du Colombier /*
4134e04225SDavid du Colombier  * various RPCs.  here is where we'd insert support for NFS v2
4234e04225SDavid du Colombier  */
4334e04225SDavid du Colombier 
4434e04225SDavid du Colombier void
portCall(SunCall * c,PortCallType type)4534e04225SDavid du Colombier portCall(SunCall *c, PortCallType type)
4634e04225SDavid du Colombier {
4734e04225SDavid du Colombier 	c->rpc.prog = PortProgram;
4834e04225SDavid du Colombier 	c->rpc.vers = PortVersion;
4934e04225SDavid du Colombier 	c->rpc.proc = type>>1;
5034e04225SDavid du Colombier 	c->rpc.iscall = !(type&1);
5134e04225SDavid du Colombier 	c->type = type;
5234e04225SDavid du Colombier }
5334e04225SDavid du Colombier 
5434e04225SDavid du Colombier int
getport(SunClient * client,uint prog,uint vers,uint prot,uint * port)5534e04225SDavid du Colombier getport(SunClient *client, uint prog, uint vers, uint prot, uint *port)
5634e04225SDavid du Colombier {
5734e04225SDavid du Colombier 	PortTGetport tx;
5834e04225SDavid du Colombier 	PortRGetport rx;
5934e04225SDavid du Colombier 
6034e04225SDavid du Colombier 	memset(&tx, 0, sizeof tx);
6134e04225SDavid du Colombier 	portCall(&tx.call, PortCallTGetport);
6234e04225SDavid du Colombier 	tx.map.prog = prog;
6334e04225SDavid du Colombier 	tx.map.vers = vers;
6434e04225SDavid du Colombier 	tx.map.prot = prot;
6534e04225SDavid du Colombier 
6634e04225SDavid du Colombier 	memset(&rx, 0, sizeof rx);
6734e04225SDavid du Colombier 	portCall(&rx.call, PortCallRGetport);
6834e04225SDavid du Colombier 
6934e04225SDavid du Colombier 	if(sunClientRpc(client, 0, &tx.call, &rx.call, nil) < 0)
7034e04225SDavid du Colombier 		return -1;
7134e04225SDavid du Colombier 	*port = rx.port;
7234e04225SDavid du Colombier 	return 0;
7334e04225SDavid du Colombier }
7434e04225SDavid du Colombier 
7534e04225SDavid du Colombier void
mountCall(Auth * a,SunCall * c,NfsMount3CallType type)7634e04225SDavid du Colombier mountCall(Auth *a, SunCall *c, NfsMount3CallType type)
7734e04225SDavid du Colombier {
7834e04225SDavid du Colombier 	c->rpc.iscall = !(type&1);
7934e04225SDavid du Colombier 	c->rpc.proc = type>>1;
8034e04225SDavid du Colombier 	c->rpc.prog = NfsMount3Program;
8134e04225SDavid du Colombier 	c->rpc.vers = NfsMount3Version;
8234e04225SDavid du Colombier 	if(c->rpc.iscall && a){
8334e04225SDavid du Colombier 		c->rpc.cred.flavor = SunAuthSys;
8434e04225SDavid du Colombier 		c->rpc.cred.data = a->data;
8534e04225SDavid du Colombier 		c->rpc.cred.ndata = a->ndata;
8634e04225SDavid du Colombier 	}
8734e04225SDavid du Colombier 	c->type = type;
8834e04225SDavid du Colombier }
8934e04225SDavid du Colombier 
9034e04225SDavid du Colombier int
mountNull(ulong tag)9134e04225SDavid du Colombier mountNull(ulong tag)
9234e04225SDavid du Colombier {
9334e04225SDavid du Colombier 	NfsMount3TNull tx;
9434e04225SDavid du Colombier 	NfsMount3RNull rx;
9534e04225SDavid du Colombier 
9634e04225SDavid du Colombier 	memset(&tx, 0, sizeof tx);
9734e04225SDavid du Colombier 	mountCall(nil, &tx.call, NfsMount3CallTNull);
9834e04225SDavid du Colombier 
9934e04225SDavid du Colombier 	memset(&rx, 0, sizeof rx);
10034e04225SDavid du Colombier 	mountCall(nil, &rx.call, NfsMount3CallTNull);
10134e04225SDavid du Colombier 
10234e04225SDavid du Colombier 	return sunClientRpc(mntcli, tag, &tx.call, &rx.call, nil);
10334e04225SDavid du Colombier }
10434e04225SDavid du Colombier 
10534e04225SDavid du Colombier int
mountMnt(Auth * a,ulong tag,char * path,Nfs3Handle * h)10634e04225SDavid du Colombier mountMnt(Auth *a, ulong tag, char *path, Nfs3Handle *h)
10734e04225SDavid du Colombier {
10834e04225SDavid du Colombier 	uchar *freeme;
10934e04225SDavid du Colombier 	NfsMount3TMnt tx;
11034e04225SDavid du Colombier 	NfsMount3RMnt rx;
11134e04225SDavid du Colombier 
11234e04225SDavid du Colombier 	memset(&tx, 0, sizeof tx);
11334e04225SDavid du Colombier 	mountCall(a, &tx.call, NfsMount3CallTMnt);
11434e04225SDavid du Colombier 	tx.path = path;
11534e04225SDavid du Colombier 
11634e04225SDavid du Colombier 	memset(&rx, 0, sizeof rx);
11734e04225SDavid du Colombier 	mountCall(a, &rx.call, NfsMount3CallRMnt);
11834e04225SDavid du Colombier 	if(sunClientRpc(mntcli, tag, &tx.call, &rx.call, &freeme) < 0)
11934e04225SDavid du Colombier 		return -1;
12034e04225SDavid du Colombier 	if(rx.status != Nfs3Ok){
12134e04225SDavid du Colombier 		nfs3Errstr(rx.status);
12234e04225SDavid du Colombier 		return -1;
12334e04225SDavid du Colombier 	}
12434e04225SDavid du Colombier if(verbose)print("handle %.*H\n", rx.len, rx.handle);
12534e04225SDavid du Colombier 	if(rx.len >= Nfs3MaxHandleSize){
12634e04225SDavid du Colombier 		free(freeme);
12734e04225SDavid du Colombier 		werrstr("server-returned handle too long");
12834e04225SDavid du Colombier 		return -1;
12934e04225SDavid du Colombier 	}
13034e04225SDavid du Colombier 	memmove(h->h, rx.handle, rx.len);
13134e04225SDavid du Colombier 	h->len = rx.len;
13234e04225SDavid du Colombier 	free(freeme);
13334e04225SDavid du Colombier 	return 0;
13434e04225SDavid du Colombier }
13534e04225SDavid du Colombier 
13634e04225SDavid du Colombier void
nfs3Call(Auth * a,SunCall * c,Nfs3CallType type)13734e04225SDavid du Colombier nfs3Call(Auth *a, SunCall *c, Nfs3CallType type)
13834e04225SDavid du Colombier {
13934e04225SDavid du Colombier 	c->rpc.iscall = !(type&1);
14034e04225SDavid du Colombier 	c->rpc.proc = type>>1;
14134e04225SDavid du Colombier 	c->rpc.prog = Nfs3Program;
14234e04225SDavid du Colombier 	c->rpc.vers = Nfs3Version;
14334e04225SDavid du Colombier 	if(c->rpc.iscall && a){
14434e04225SDavid du Colombier 		c->rpc.cred.flavor = SunAuthSys;
14534e04225SDavid du Colombier 		c->rpc.cred.data = a->data;
14634e04225SDavid du Colombier 		c->rpc.cred.ndata = a->ndata;
14734e04225SDavid du Colombier 	}
14834e04225SDavid du Colombier 	c->type = type;
14934e04225SDavid du Colombier }
15034e04225SDavid du Colombier 
15134e04225SDavid du Colombier int
nfsNull(ulong tag)15234e04225SDavid du Colombier nfsNull(ulong tag)
15334e04225SDavid du Colombier {
15434e04225SDavid du Colombier 	Nfs3TNull tx;
15534e04225SDavid du Colombier 	Nfs3RNull rx;
15634e04225SDavid du Colombier 
15734e04225SDavid du Colombier 	memset(&tx, 0, sizeof tx);
15834e04225SDavid du Colombier 	nfs3Call(nil, &tx.call, Nfs3CallTNull);
15934e04225SDavid du Colombier 
16034e04225SDavid du Colombier 	memset(&rx, 0, sizeof rx);
16134e04225SDavid du Colombier 	nfs3Call(nil, &rx.call, Nfs3CallTNull);
16234e04225SDavid du Colombier 
16334e04225SDavid du Colombier 	return sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil);
16434e04225SDavid du Colombier }
16534e04225SDavid du Colombier 
16634e04225SDavid du Colombier int
nfsGetattr(Auth * a,ulong tag,Nfs3Handle * h,Nfs3Attr * attr)16734e04225SDavid du Colombier nfsGetattr(Auth *a, ulong tag, Nfs3Handle *h, Nfs3Attr *attr)
16834e04225SDavid du Colombier {
16934e04225SDavid du Colombier 	Nfs3TGetattr tx;
17034e04225SDavid du Colombier 	Nfs3RGetattr rx;
17134e04225SDavid du Colombier 
17234e04225SDavid du Colombier 	memset(&tx, 0, sizeof tx);
17334e04225SDavid du Colombier 	nfs3Call(a, &tx.call, Nfs3CallTGetattr);
17434e04225SDavid du Colombier 	tx.handle = *h;
17534e04225SDavid du Colombier 
17634e04225SDavid du Colombier 	memset(&rx, 0, sizeof rx);
17734e04225SDavid du Colombier 	nfs3Call(a, &rx.call, Nfs3CallRGetattr);
17834e04225SDavid du Colombier 
17934e04225SDavid du Colombier 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
18034e04225SDavid du Colombier 		return -1;
18134e04225SDavid du Colombier 	if(rx.status != Nfs3Ok){
18234e04225SDavid du Colombier 		nfs3Errstr(rx.status);
18334e04225SDavid du Colombier 		return -1;
18434e04225SDavid du Colombier 	}
18534e04225SDavid du Colombier 
18634e04225SDavid du Colombier 	*attr = rx.attr;
18734e04225SDavid du Colombier 	return 0;
18834e04225SDavid du Colombier }
18934e04225SDavid du Colombier 
19034e04225SDavid du Colombier int
nfsAccess(Auth * a,ulong tag,Nfs3Handle * h,ulong want,ulong * got,u1int * have,Nfs3Attr * attr)19134e04225SDavid du Colombier nfsAccess(Auth *a, ulong tag, Nfs3Handle *h, ulong want, ulong *got, u1int *have, Nfs3Attr *attr)
19234e04225SDavid du Colombier {
19334e04225SDavid du Colombier 	Nfs3TAccess tx;
19434e04225SDavid du Colombier 	Nfs3RAccess rx;
19534e04225SDavid du Colombier 
19634e04225SDavid du Colombier 	memset(&tx, 0, sizeof tx);
19734e04225SDavid du Colombier 	nfs3Call(a, &tx.call, Nfs3CallTAccess);
19834e04225SDavid du Colombier 	tx.handle = *h;
19934e04225SDavid du Colombier 	tx.access = want;
20034e04225SDavid du Colombier 
20134e04225SDavid du Colombier 	memset(&rx, 0, sizeof rx);
20234e04225SDavid du Colombier 	nfs3Call(a, &rx.call, Nfs3CallRAccess);
20334e04225SDavid du Colombier 
20434e04225SDavid du Colombier 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
20534e04225SDavid du Colombier 		return -1;
20634e04225SDavid du Colombier 	if(rx.status != Nfs3Ok){
20734e04225SDavid du Colombier 		nfs3Errstr(rx.status);
20834e04225SDavid du Colombier 		return -1;
20934e04225SDavid du Colombier 	}
21034e04225SDavid du Colombier 
21134e04225SDavid du Colombier 	*got = rx.access;
21234e04225SDavid du Colombier 
21334e04225SDavid du Colombier 	*have = rx.haveAttr;
21434e04225SDavid du Colombier 	if(rx.haveAttr)
21534e04225SDavid du Colombier 		*attr = rx.attr;
21634e04225SDavid du Colombier 	return 0;
21734e04225SDavid du Colombier }
21834e04225SDavid du Colombier 
21934e04225SDavid du Colombier int
nfsMkdir(Auth * a,ulong tag,Nfs3Handle * h,char * name,Nfs3Handle * nh,ulong mode,uint gid,u1int * have,Nfs3Attr * attr)22034e04225SDavid du Colombier nfsMkdir(Auth *a, ulong tag, Nfs3Handle *h, char *name, Nfs3Handle *nh, ulong mode, uint gid,
22134e04225SDavid du Colombier 	u1int *have, Nfs3Attr *attr)
22234e04225SDavid du Colombier {
22334e04225SDavid du Colombier 	Nfs3TMkdir tx;
22434e04225SDavid du Colombier 	Nfs3RMkdir rx;
22534e04225SDavid du Colombier 
22634e04225SDavid du Colombier 	memset(&tx, 0, sizeof tx);
22734e04225SDavid du Colombier 	nfs3Call(a, &tx.call, Nfs3CallTMkdir);
22834e04225SDavid du Colombier 	tx.handle = *h;
22934e04225SDavid du Colombier 	tx.name = name;
23034e04225SDavid du Colombier 	tx.attr.setMode = 1;
23134e04225SDavid du Colombier 	tx.attr.mode = mode;
23234e04225SDavid du Colombier 	tx.attr.setGid = 1;
23334e04225SDavid du Colombier 	tx.attr.gid = gid;
23434e04225SDavid du Colombier 
23534e04225SDavid du Colombier 	memset(&rx, 0, sizeof rx);
23634e04225SDavid du Colombier 	nfs3Call(a, &rx.call, Nfs3CallRMkdir);
23734e04225SDavid du Colombier 
23834e04225SDavid du Colombier 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
23934e04225SDavid du Colombier 		return -1;
24034e04225SDavid du Colombier 	if(rx.status != Nfs3Ok){
24134e04225SDavid du Colombier 		nfs3Errstr(rx.status);
24234e04225SDavid du Colombier 		return -1;
24334e04225SDavid du Colombier 	}
24434e04225SDavid du Colombier 
24534e04225SDavid du Colombier 	if(!rx.haveHandle){
24634e04225SDavid du Colombier 		werrstr("nfs mkdir did not return handle");
24734e04225SDavid du Colombier 		return -1;
24834e04225SDavid du Colombier 	}
24934e04225SDavid du Colombier 	*nh = rx.handle;
25034e04225SDavid du Colombier 
25134e04225SDavid du Colombier 	*have = rx.haveAttr;
25234e04225SDavid du Colombier 	if(rx.haveAttr)
25334e04225SDavid du Colombier 		*attr = rx.attr;
25434e04225SDavid du Colombier 	return 0;
25534e04225SDavid du Colombier }
25634e04225SDavid du Colombier 
25734e04225SDavid du Colombier int
nfsCreate(Auth * a,ulong tag,Nfs3Handle * h,char * name,Nfs3Handle * nh,ulong mode,uint gid,u1int * have,Nfs3Attr * attr)25834e04225SDavid du Colombier nfsCreate(Auth *a, ulong tag, Nfs3Handle *h, char *name, Nfs3Handle *nh, ulong mode, uint gid,
25934e04225SDavid du Colombier 	u1int *have, Nfs3Attr *attr)
26034e04225SDavid du Colombier {
26134e04225SDavid du Colombier 	Nfs3TCreate tx;
26234e04225SDavid du Colombier 	Nfs3RCreate rx;
26334e04225SDavid du Colombier 
26434e04225SDavid du Colombier 	memset(&tx, 0, sizeof tx);
26534e04225SDavid du Colombier 	nfs3Call(a, &tx.call, Nfs3CallTCreate);
26634e04225SDavid du Colombier 	tx.handle = *h;
26734e04225SDavid du Colombier 	tx.name = name;
26834e04225SDavid du Colombier 	tx.attr.setMode = 1;
26934e04225SDavid du Colombier 	tx.attr.mode = mode;
27034e04225SDavid du Colombier 	tx.attr.setGid = 1;
27134e04225SDavid du Colombier 	tx.attr.gid = gid;
27234e04225SDavid du Colombier 
27334e04225SDavid du Colombier 	memset(&rx, 0, sizeof rx);
27434e04225SDavid du Colombier 	nfs3Call(a, &rx.call, Nfs3CallRCreate);
27534e04225SDavid du Colombier 
27634e04225SDavid du Colombier 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
27734e04225SDavid du Colombier 		return -1;
27834e04225SDavid du Colombier 	if(rx.status != Nfs3Ok){
27934e04225SDavid du Colombier 		nfs3Errstr(rx.status);
28034e04225SDavid du Colombier 		return -1;
28134e04225SDavid du Colombier 	}
28234e04225SDavid du Colombier 
28334e04225SDavid du Colombier 	if(!rx.haveHandle){
28434e04225SDavid du Colombier 		werrstr("nfs create did not return handle");
28534e04225SDavid du Colombier 		return -1;
28634e04225SDavid du Colombier 	}
28734e04225SDavid du Colombier 	*nh = rx.handle;
28834e04225SDavid du Colombier 
28934e04225SDavid du Colombier 	*have = rx.haveAttr;
29034e04225SDavid du Colombier 	if(rx.haveAttr)
29134e04225SDavid du Colombier 		*attr = rx.attr;
29234e04225SDavid du Colombier 	return 0;
29334e04225SDavid du Colombier }
29434e04225SDavid du Colombier 
29534e04225SDavid du Colombier int
nfsRead(Auth * a,ulong tag,Nfs3Handle * h,u32int count,u64int offset,uchar ** pp,u32int * pcount,uchar ** pfreeme)29634e04225SDavid du Colombier nfsRead(Auth *a, ulong tag, Nfs3Handle *h, u32int count, u64int offset,
29734e04225SDavid du Colombier 	uchar **pp, u32int *pcount, uchar **pfreeme)
29834e04225SDavid du Colombier {
29934e04225SDavid du Colombier 	uchar *freeme;
30034e04225SDavid du Colombier 	Nfs3TRead tx;
30134e04225SDavid du Colombier 	Nfs3RRead rx;
30234e04225SDavid du Colombier 
30334e04225SDavid du Colombier 	memset(&tx, 0, sizeof tx);
30434e04225SDavid du Colombier 	nfs3Call(a, &tx.call, Nfs3CallTRead);
30534e04225SDavid du Colombier 	tx.handle = *h;
30634e04225SDavid du Colombier 	tx.count = count;
30734e04225SDavid du Colombier 	tx.offset = offset;
30834e04225SDavid du Colombier 
30934e04225SDavid du Colombier 	memset(&rx, 0, sizeof rx);
31034e04225SDavid du Colombier 	nfs3Call(a, &rx.call, Nfs3CallRRead);
31134e04225SDavid du Colombier 
31234e04225SDavid du Colombier 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, &freeme) < 0)
31334e04225SDavid du Colombier 		return -1;
31434e04225SDavid du Colombier 	if(rx.status != Nfs3Ok){
31534e04225SDavid du Colombier 		nfs3Errstr(rx.status);
31634e04225SDavid du Colombier 		return -1;
31734e04225SDavid du Colombier 	}
31834e04225SDavid du Colombier 	if(rx.count != rx.ndata){
31934e04225SDavid du Colombier 		werrstr("nfs read returned count=%ud ndata=%ud", (uint)rx.count, (uint)rx.ndata);
32034e04225SDavid du Colombier 		free(freeme);
32134e04225SDavid du Colombier 		return -1;
32234e04225SDavid du Colombier 	}
32334e04225SDavid du Colombier 	*pfreeme = freeme;
32434e04225SDavid du Colombier 	*pcount = rx.count;
32534e04225SDavid du Colombier 	*pp = rx.data;
32634e04225SDavid du Colombier 	return 0;
32734e04225SDavid du Colombier }
32834e04225SDavid du Colombier 
32934e04225SDavid du Colombier int
nfsWrite(Auth * a,ulong tag,Nfs3Handle * h,uchar * data,u32int count,u64int offset,u32int * pcount)33034e04225SDavid du Colombier nfsWrite(Auth *a, ulong tag, Nfs3Handle *h, uchar *data, u32int count, u64int offset, u32int *pcount)
33134e04225SDavid du Colombier {
33234e04225SDavid du Colombier 	Nfs3TWrite tx;
33334e04225SDavid du Colombier 	Nfs3RWrite rx;
33434e04225SDavid du Colombier 
33534e04225SDavid du Colombier 	memset(&tx, 0, sizeof tx);
33634e04225SDavid du Colombier 	nfs3Call(a, &tx.call, Nfs3CallTWrite);
33734e04225SDavid du Colombier 	tx.handle = *h;
33834e04225SDavid du Colombier 	tx.count = count;
33934e04225SDavid du Colombier 	tx.offset = offset;
34034e04225SDavid du Colombier 	tx.data = data;
3416ff5e913SDavid du Colombier 	tx.ndata = count;
34234e04225SDavid du Colombier 
34334e04225SDavid du Colombier 	memset(&rx, 0, sizeof rx);
34434e04225SDavid du Colombier 	nfs3Call(a, &rx.call, Nfs3CallRWrite);
34534e04225SDavid du Colombier 
34634e04225SDavid du Colombier 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
34734e04225SDavid du Colombier 		return -1;
34834e04225SDavid du Colombier 	if(rx.status != Nfs3Ok){
34934e04225SDavid du Colombier 		nfs3Errstr(rx.status);
35034e04225SDavid du Colombier 		return -1;
35134e04225SDavid du Colombier 	}
35234e04225SDavid du Colombier 
35334e04225SDavid du Colombier 	*pcount = rx.count;
35434e04225SDavid du Colombier 	return 0;
35534e04225SDavid du Colombier }
35634e04225SDavid du Colombier 
35734e04225SDavid du Colombier int
nfsRmdir(Auth * a,ulong tag,Nfs3Handle * h,char * name)35834e04225SDavid du Colombier nfsRmdir(Auth *a, ulong tag, Nfs3Handle *h, char *name)
35934e04225SDavid du Colombier {
36034e04225SDavid du Colombier 	Nfs3TRmdir tx;
36134e04225SDavid du Colombier 	Nfs3RRmdir rx;
36234e04225SDavid du Colombier 
36334e04225SDavid du Colombier 	memset(&tx, 0, sizeof tx);
36434e04225SDavid du Colombier 	nfs3Call(a, &tx.call, Nfs3CallTRmdir);
36534e04225SDavid du Colombier 	tx.handle = *h;
36634e04225SDavid du Colombier 	tx.name = name;
36734e04225SDavid du Colombier 
36834e04225SDavid du Colombier 	memset(&rx, 0, sizeof rx);
36934e04225SDavid du Colombier 	nfs3Call(a, &rx.call, Nfs3CallRRmdir);
37034e04225SDavid du Colombier 
37134e04225SDavid du Colombier 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
37234e04225SDavid du Colombier 		return -1;
37334e04225SDavid du Colombier 	if(rx.status != Nfs3Ok){
37434e04225SDavid du Colombier 		nfs3Errstr(rx.status);
37534e04225SDavid du Colombier 		return -1;
37634e04225SDavid du Colombier 	}
37734e04225SDavid du Colombier 	return 0;
37834e04225SDavid du Colombier }
37934e04225SDavid du Colombier 
38034e04225SDavid du Colombier int
nfsRemove(Auth * a,ulong tag,Nfs3Handle * h,char * name)38134e04225SDavid du Colombier nfsRemove(Auth *a, ulong tag, Nfs3Handle *h, char *name)
38234e04225SDavid du Colombier {
38334e04225SDavid du Colombier 	Nfs3TRemove tx;
38434e04225SDavid du Colombier 	Nfs3RRemove rx;
38534e04225SDavid du Colombier 
38634e04225SDavid du Colombier 	memset(&tx, 0, sizeof tx);
38734e04225SDavid du Colombier 	nfs3Call(a, &tx.call, Nfs3CallTRemove);
38834e04225SDavid du Colombier 	tx.handle = *h;
38934e04225SDavid du Colombier 	tx.name = name;
39034e04225SDavid du Colombier 
39134e04225SDavid du Colombier 	memset(&rx, 0, sizeof rx);
39234e04225SDavid du Colombier 	nfs3Call(a, &rx.call, Nfs3CallRRemove);
39334e04225SDavid du Colombier 
39434e04225SDavid du Colombier 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
39534e04225SDavid du Colombier 		return -1;
39634e04225SDavid du Colombier 	if(rx.status != Nfs3Ok){
39734e04225SDavid du Colombier 		nfs3Errstr(rx.status);
39834e04225SDavid du Colombier 		return -1;
39934e04225SDavid du Colombier 	}
40034e04225SDavid du Colombier 	return 0;
40134e04225SDavid du Colombier }
40234e04225SDavid du Colombier 
40334e04225SDavid du Colombier int
nfsRename(Auth * a,ulong tag,Nfs3Handle * h,char * name,Nfs3Handle * th,char * tname)40434e04225SDavid du Colombier nfsRename(Auth *a, ulong tag, Nfs3Handle *h, char *name, Nfs3Handle *th, char *tname)
40534e04225SDavid du Colombier {
40634e04225SDavid du Colombier 	Nfs3TRename tx;
40734e04225SDavid du Colombier 	Nfs3RRename rx;
40834e04225SDavid du Colombier 
40934e04225SDavid du Colombier 	memset(&tx, 0, sizeof tx);
41034e04225SDavid du Colombier 	nfs3Call(a, &tx.call, Nfs3CallTRename);
41134e04225SDavid du Colombier 	tx.from.handle = *h;
41234e04225SDavid du Colombier 	tx.from.name = name;
41334e04225SDavid du Colombier 	tx.to.handle = *th;
41434e04225SDavid du Colombier 	tx.to.name = tname;
41534e04225SDavid du Colombier 
41634e04225SDavid du Colombier 	memset(&rx, 0, sizeof rx);
41734e04225SDavid du Colombier 	nfs3Call(a, &rx.call, Nfs3CallRRename);
41834e04225SDavid du Colombier 
41934e04225SDavid du Colombier 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
42034e04225SDavid du Colombier 		return -1;
42134e04225SDavid du Colombier 	if(rx.status != Nfs3Ok){
42234e04225SDavid du Colombier 		nfs3Errstr(rx.status);
42334e04225SDavid du Colombier 		return -1;
42434e04225SDavid du Colombier 	}
42534e04225SDavid du Colombier 	return 0;
42634e04225SDavid du Colombier }
42734e04225SDavid du Colombier 
42834e04225SDavid du Colombier int
nfsSetattr(Auth * a,ulong tag,Nfs3Handle * h,Nfs3SetAttr * attr)42934e04225SDavid du Colombier nfsSetattr(Auth *a, ulong tag, Nfs3Handle *h, Nfs3SetAttr *attr)
43034e04225SDavid du Colombier {
43134e04225SDavid du Colombier 	Nfs3TSetattr tx;
43234e04225SDavid du Colombier 	Nfs3RSetattr rx;
43334e04225SDavid du Colombier 
43434e04225SDavid du Colombier 	memset(&tx, 0, sizeof tx);
43534e04225SDavid du Colombier 	nfs3Call(a, &tx.call, Nfs3CallTSetattr);
43634e04225SDavid du Colombier 	tx.handle = *h;
43734e04225SDavid du Colombier 	tx.attr = *attr;
43834e04225SDavid du Colombier 
43934e04225SDavid du Colombier 	memset(&rx, 0, sizeof rx);
44034e04225SDavid du Colombier 	nfs3Call(a, &rx.call, Nfs3CallRSetattr);
44134e04225SDavid du Colombier 
44234e04225SDavid du Colombier 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
44334e04225SDavid du Colombier 		return -1;
44434e04225SDavid du Colombier 	if(rx.status != Nfs3Ok){
44534e04225SDavid du Colombier 		nfs3Errstr(rx.status);
44634e04225SDavid du Colombier 		return -1;
44734e04225SDavid du Colombier 	}
44834e04225SDavid du Colombier 	return 0;
44934e04225SDavid du Colombier }
45034e04225SDavid du Colombier 
45134e04225SDavid du Colombier int
nfsCommit(Auth * a,ulong tag,Nfs3Handle * h)45234e04225SDavid du Colombier nfsCommit(Auth *a, ulong tag, Nfs3Handle *h)
45334e04225SDavid du Colombier {
45434e04225SDavid du Colombier 	Nfs3TCommit tx;
45534e04225SDavid du Colombier 	Nfs3RCommit rx;
45634e04225SDavid du Colombier 
45734e04225SDavid du Colombier 	memset(&tx, 0, sizeof tx);
45834e04225SDavid du Colombier 	nfs3Call(a, &tx.call, Nfs3CallTCommit);
45934e04225SDavid du Colombier 	tx.handle = *h;
46034e04225SDavid du Colombier 
46134e04225SDavid du Colombier 	memset(&rx, 0, sizeof rx);
46234e04225SDavid du Colombier 	nfs3Call(a, &rx.call, Nfs3CallRCommit);
46334e04225SDavid du Colombier 
46434e04225SDavid du Colombier 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
46534e04225SDavid du Colombier 		return -1;
46634e04225SDavid du Colombier 
46734e04225SDavid du Colombier 	if(rx.status != Nfs3Ok){
46834e04225SDavid du Colombier 		nfs3Errstr(rx.status);
46934e04225SDavid du Colombier 		return -1;
47034e04225SDavid du Colombier 	}
47134e04225SDavid du Colombier 	return 0;
47234e04225SDavid du Colombier }
47334e04225SDavid du Colombier 
47434e04225SDavid du Colombier int
nfsLookup(Auth * a,ulong tag,Nfs3Handle * h,char * name,Nfs3Handle * nh,u1int * have,Nfs3Attr * attr)47534e04225SDavid du Colombier nfsLookup(Auth *a, ulong tag, Nfs3Handle *h, char *name, Nfs3Handle *nh, u1int *have, Nfs3Attr *attr)
47634e04225SDavid du Colombier {
47734e04225SDavid du Colombier 	Nfs3TLookup tx;
47834e04225SDavid du Colombier 	Nfs3RLookup rx;
47934e04225SDavid du Colombier 
48034e04225SDavid du Colombier 	memset(&tx, 0, sizeof tx);
48134e04225SDavid du Colombier 	nfs3Call(a, &tx.call, Nfs3CallTLookup);
48234e04225SDavid du Colombier 	tx.handle = *h;
48334e04225SDavid du Colombier 	tx.name = name;
48434e04225SDavid du Colombier 
48534e04225SDavid du Colombier 	memset(&rx, 0, sizeof rx);
48634e04225SDavid du Colombier 	nfs3Call(a, &rx.call, Nfs3CallRLookup);
48734e04225SDavid du Colombier 
48834e04225SDavid du Colombier 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
48934e04225SDavid du Colombier 		return -1;
49034e04225SDavid du Colombier 
49134e04225SDavid du Colombier 	if(rx.status != Nfs3Ok){
49234e04225SDavid du Colombier 		nfs3Errstr(rx.status);
49334e04225SDavid du Colombier 		return -1;
49434e04225SDavid du Colombier 	}
49534e04225SDavid du Colombier 	*nh = rx.handle;
49634e04225SDavid du Colombier 	*have = rx.haveAttr;
49734e04225SDavid du Colombier 	if(rx.haveAttr)
49834e04225SDavid du Colombier 		*attr = rx.attr;
49934e04225SDavid du Colombier 	return 0;
50034e04225SDavid du Colombier }
50134e04225SDavid du Colombier 
50234e04225SDavid du Colombier int
nfsReadDirPlus(Auth * a,ulong tag,Nfs3Handle * h,u32int count,u64int cookie,uchar ** pp,u32int * pcount,int (** unpack)(uchar *,uchar *,uchar **,Nfs3Entry *),uchar ** pfreeme)50334e04225SDavid du Colombier nfsReadDirPlus(Auth *a, ulong tag, Nfs3Handle *h, u32int count, u64int cookie, uchar **pp,
50434e04225SDavid du Colombier 	u32int *pcount, int (**unpack)(uchar*, uchar*, uchar**, Nfs3Entry*), uchar **pfreeme)
50534e04225SDavid du Colombier {
50634e04225SDavid du Colombier 	Nfs3TReadDirPlus tx;
50734e04225SDavid du Colombier 	Nfs3RReadDirPlus rx;
50834e04225SDavid du Colombier 
50934e04225SDavid du Colombier 	memset(&tx, 0, sizeof tx);
51034e04225SDavid du Colombier 	nfs3Call(a, &tx.call, Nfs3CallTReadDirPlus);
51134e04225SDavid du Colombier 	tx.handle = *h;
51234e04225SDavid du Colombier 	tx.maxCount = count;
51334e04225SDavid du Colombier 	tx.dirCount = 1000;
51434e04225SDavid du Colombier 	tx.cookie = cookie;
51534e04225SDavid du Colombier 
51634e04225SDavid du Colombier 	memset(&rx, 0, sizeof rx);
51734e04225SDavid du Colombier 	nfs3Call(a, &rx.call, Nfs3CallRReadDirPlus);
51834e04225SDavid du Colombier 
51934e04225SDavid du Colombier 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, pfreeme) < 0)
52034e04225SDavid du Colombier 		return -1;
52134e04225SDavid du Colombier 	if(rx.status != Nfs3Ok){
52234e04225SDavid du Colombier 		free(*pfreeme);
52334e04225SDavid du Colombier 		*pfreeme = 0;
52434e04225SDavid du Colombier 		nfs3Errstr(rx.status);
52534e04225SDavid du Colombier 		return -1;
52634e04225SDavid du Colombier 	}
52734e04225SDavid du Colombier 
52834e04225SDavid du Colombier 	*unpack = nfs3EntryPlusUnpack;
52934e04225SDavid du Colombier 	*pcount = rx.count;
53034e04225SDavid du Colombier 	*pp = rx.data;
53134e04225SDavid du Colombier 	return 0;
53234e04225SDavid du Colombier }
53334e04225SDavid du Colombier 
53434e04225SDavid du Colombier int
nfsReadDir(Auth * a,ulong tag,Nfs3Handle * h,u32int count,u64int cookie,uchar ** pp,u32int * pcount,int (** unpack)(uchar *,uchar *,uchar **,Nfs3Entry *),uchar ** pfreeme)53534e04225SDavid du Colombier nfsReadDir(Auth *a, ulong tag, Nfs3Handle *h, u32int count, u64int cookie, uchar **pp,
53634e04225SDavid du Colombier 	u32int *pcount, int (**unpack)(uchar*, uchar*, uchar**, Nfs3Entry*), uchar **pfreeme)
53734e04225SDavid du Colombier {
53834e04225SDavid du Colombier 	/* BUG: try readdirplus */
53934e04225SDavid du Colombier 	char e[ERRMAX];
54034e04225SDavid du Colombier 	Nfs3TReadDir tx;
54134e04225SDavid du Colombier 	Nfs3RReadDir rx;
54234e04225SDavid du Colombier 
54334e04225SDavid du Colombier 	if(readplus!=-1){
54434e04225SDavid du Colombier 		if(nfsReadDirPlus(a, tag, h, count, cookie, pp, pcount, unpack, pfreeme) == 0){
54534e04225SDavid du Colombier 			readplus = 1;
54634e04225SDavid du Colombier 			return 0;
54734e04225SDavid du Colombier 		}
54834e04225SDavid du Colombier 		if(readplus == 0){
54934e04225SDavid du Colombier 			rerrstr(e, sizeof e);
550fb7f0c93SDavid du Colombier 			if(strstr(e, "procedure unavailable") || strstr(e, "not supported"))
55134e04225SDavid du Colombier 				readplus = -1;
55234e04225SDavid du Colombier 		}
5536ff5e913SDavid du Colombier 		if(readplus == 0)
5546ff5e913SDavid du Colombier 			fprint(2, "readdirplus: %r\n");
55534e04225SDavid du Colombier 	}
55634e04225SDavid du Colombier 	if(readplus == 1)
55734e04225SDavid du Colombier 		return -1;
55834e04225SDavid du Colombier 
55934e04225SDavid du Colombier 	memset(&tx, 0, sizeof tx);
56034e04225SDavid du Colombier 	nfs3Call(a, &tx.call, Nfs3CallTReadDir);
56134e04225SDavid du Colombier 	tx.handle = *h;
56234e04225SDavid du Colombier 	tx.count = count;
56334e04225SDavid du Colombier 	tx.cookie = cookie;
56434e04225SDavid du Colombier 
56534e04225SDavid du Colombier 	memset(&rx, 0, sizeof rx);
56634e04225SDavid du Colombier 	nfs3Call(a, &rx.call, Nfs3CallRReadDir);
56734e04225SDavid du Colombier 
56834e04225SDavid du Colombier 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, pfreeme) < 0)
56934e04225SDavid du Colombier 		return -1;
57034e04225SDavid du Colombier 	if(rx.status != Nfs3Ok){
57134e04225SDavid du Colombier 		free(*pfreeme);
57234e04225SDavid du Colombier 		*pfreeme = 0;
57334e04225SDavid du Colombier 		nfs3Errstr(rx.status);
57434e04225SDavid du Colombier 		return -1;
57534e04225SDavid du Colombier 	}
57634e04225SDavid du Colombier 
57734e04225SDavid du Colombier 	/* readplus failed but read succeeded */
57834e04225SDavid du Colombier 	readplus = -1;
57934e04225SDavid du Colombier 
58034e04225SDavid du Colombier 	*unpack = nfs3EntryUnpack;
58134e04225SDavid du Colombier 	*pcount = rx.count;
58234e04225SDavid du Colombier 	*pp = rx.data;
58334e04225SDavid du Colombier 	return 0;
58434e04225SDavid du Colombier }
58534e04225SDavid du Colombier 
58634e04225SDavid du Colombier /*
58734e04225SDavid du Colombier  * name <-> int translation
58834e04225SDavid du Colombier  */
58934e04225SDavid du Colombier typedef struct Map Map;
59034e04225SDavid du Colombier typedef struct User User;
59134e04225SDavid du Colombier typedef struct Group Group;
59234e04225SDavid du Colombier 
59334e04225SDavid du Colombier Map *map;
59434e04225SDavid du Colombier Map emptymap;
59534e04225SDavid du Colombier 
59634e04225SDavid du Colombier struct User
59734e04225SDavid du Colombier {
59834e04225SDavid du Colombier 	char *name;
59934e04225SDavid du Colombier 	uint uid;
60034e04225SDavid du Colombier 	uint gid;
60134e04225SDavid du Colombier 	uint g[16];
60234e04225SDavid du Colombier 	uint ng;
60334e04225SDavid du Colombier 	uchar *auth;
60434e04225SDavid du Colombier 	int nauth;
60534e04225SDavid du Colombier };
60634e04225SDavid du Colombier 
60734e04225SDavid du Colombier struct Group
60834e04225SDavid du Colombier {
60934e04225SDavid du Colombier 	char *name;	/* same pos as in User struct */
61034e04225SDavid du Colombier 	uint gid;	/* same pos as in User struct */
61134e04225SDavid du Colombier };
61234e04225SDavid du Colombier 
61334e04225SDavid du Colombier struct Map
61434e04225SDavid du Colombier {
61534e04225SDavid du Colombier 	int nuser;
61634e04225SDavid du Colombier 	int ngroup;
61734e04225SDavid du Colombier 	User *user;
61834e04225SDavid du Colombier 	User **ubyname;
61934e04225SDavid du Colombier 	User **ubyid;
62034e04225SDavid du Colombier 	Group *group;
62134e04225SDavid du Colombier 	Group **gbyname;
62234e04225SDavid du Colombier 	Group **gbyid;
62334e04225SDavid du Colombier };
62434e04225SDavid du Colombier 
62534e04225SDavid du Colombier User*
finduser(User ** u,int nu,char * s)62634e04225SDavid du Colombier finduser(User **u, int nu, char *s)
62734e04225SDavid du Colombier {
62834e04225SDavid du Colombier 	int lo, hi, mid, n;
62934e04225SDavid du Colombier 
63034e04225SDavid du Colombier 	hi = nu;
63134e04225SDavid du Colombier 	lo = 0;
63234e04225SDavid du Colombier 	while(hi > lo){
63334e04225SDavid du Colombier 		mid = (lo+hi)/2;
63434e04225SDavid du Colombier 		n = strcmp(u[mid]->name, s);
63534e04225SDavid du Colombier 		if(n == 0)
63634e04225SDavid du Colombier 			return u[mid];
63734e04225SDavid du Colombier 		if(n < 0)
63834e04225SDavid du Colombier 			lo = mid+1;
63934e04225SDavid du Colombier 		else
64034e04225SDavid du Colombier 			hi = mid;
64134e04225SDavid du Colombier 	}
64234e04225SDavid du Colombier 	return nil;
64334e04225SDavid du Colombier }
64434e04225SDavid du Colombier 
64534e04225SDavid du Colombier int
strtoid(User ** u,int nu,char * s,u32int * id)64634e04225SDavid du Colombier strtoid(User **u, int nu, char *s, u32int *id)
64734e04225SDavid du Colombier {
64834e04225SDavid du Colombier 	u32int x;
64934e04225SDavid du Colombier 	char *p;
65034e04225SDavid du Colombier 	User *uu;
65134e04225SDavid du Colombier 
65234e04225SDavid du Colombier 	x = strtoul(s, &p, 10);
65334e04225SDavid du Colombier 	if(*s != 0 && *p == 0){
65434e04225SDavid du Colombier 		*id = x;
65534e04225SDavid du Colombier 		return 0;
65634e04225SDavid du Colombier 	}
65734e04225SDavid du Colombier 
65834e04225SDavid du Colombier 	uu = finduser(u, nu, s);
65934e04225SDavid du Colombier 	if(uu == nil)
66034e04225SDavid du Colombier 		return -1;
66134e04225SDavid du Colombier 	*id = uu->uid;
66234e04225SDavid du Colombier 	return 0;
66334e04225SDavid du Colombier }
66434e04225SDavid du Colombier 
66534e04225SDavid du Colombier char*
idtostr(User ** u,int nu,u32int id)66634e04225SDavid du Colombier idtostr(User **u, int nu, u32int id)
66734e04225SDavid du Colombier {
66834e04225SDavid du Colombier 	char buf[32];
66934e04225SDavid du Colombier 	int lo, hi, mid;
67034e04225SDavid du Colombier 
67134e04225SDavid du Colombier 	hi = nu;
67234e04225SDavid du Colombier 	lo = 0;
67334e04225SDavid du Colombier 	while(hi > lo){
67434e04225SDavid du Colombier 		mid = (lo+hi)/2;
67534e04225SDavid du Colombier 		if(u[mid]->uid == id)
67634e04225SDavid du Colombier 			return estrdup9p(u[mid]->name);
67734e04225SDavid du Colombier 		if(u[mid]->uid < id)
67834e04225SDavid du Colombier 			lo = mid+1;
67934e04225SDavid du Colombier 		else
68034e04225SDavid du Colombier 			hi = mid;
68134e04225SDavid du Colombier 	}
68234e04225SDavid du Colombier 	snprint(buf, sizeof buf, "%ud", id);
68334e04225SDavid du Colombier 	return estrdup9p(buf);
68434e04225SDavid du Colombier }
68534e04225SDavid du Colombier char*
uidtostr(u32int uid)68634e04225SDavid du Colombier uidtostr(u32int uid)
68734e04225SDavid du Colombier {
68834e04225SDavid du Colombier 	return idtostr(map->ubyid, map->nuser, uid);
68934e04225SDavid du Colombier }
69034e04225SDavid du Colombier 
69134e04225SDavid du Colombier char*
gidtostr(u32int gid)69234e04225SDavid du Colombier gidtostr(u32int gid)
69334e04225SDavid du Colombier {
69434e04225SDavid du Colombier 	return idtostr((User**)map->gbyid, map->ngroup, gid);
69534e04225SDavid du Colombier }
69634e04225SDavid du Colombier 
69734e04225SDavid du Colombier int
strtouid(char * s,u32int * id)69834e04225SDavid du Colombier strtouid(char *s, u32int *id)
69934e04225SDavid du Colombier {
70034e04225SDavid du Colombier 	return strtoid(map->ubyname, map->nuser, s, id);
70134e04225SDavid du Colombier }
70234e04225SDavid du Colombier 
70334e04225SDavid du Colombier int
strtogid(char * s,u32int * id)70434e04225SDavid du Colombier strtogid(char *s, u32int *id)
70534e04225SDavid du Colombier {
70634e04225SDavid du Colombier 	return strtoid((User**)map->gbyid, map->ngroup, s, id);
70734e04225SDavid du Colombier }
70834e04225SDavid du Colombier 
70934e04225SDavid du Colombier 
71034e04225SDavid du Colombier int
idcmp(const void * va,const void * vb)71134e04225SDavid du Colombier idcmp(const void *va, const void *vb)
71234e04225SDavid du Colombier {
71334e04225SDavid du Colombier 	User **a, **b;
71434e04225SDavid du Colombier 
71534e04225SDavid du Colombier 	a = (User**)va;
71634e04225SDavid du Colombier 	b = (User**)vb;
71734e04225SDavid du Colombier 	return (*a)->uid - (*b)->uid;
71834e04225SDavid du Colombier }
71934e04225SDavid du Colombier 
72034e04225SDavid du Colombier int
namecmp(const void * va,const void * vb)72134e04225SDavid du Colombier namecmp(const void *va, const void *vb)
72234e04225SDavid du Colombier {
72334e04225SDavid du Colombier 	User **a, **b;
72434e04225SDavid du Colombier 
72534e04225SDavid du Colombier 	a = (User**)va;
72634e04225SDavid du Colombier 	b = (User**)vb;
72734e04225SDavid du Colombier 	return strcmp((*a)->name, (*b)->name);
72834e04225SDavid du Colombier }
72934e04225SDavid du Colombier 
73034e04225SDavid du Colombier void
closemap(Map * m)73134e04225SDavid du Colombier closemap(Map *m)
73234e04225SDavid du Colombier {
73334e04225SDavid du Colombier 	int i;
73434e04225SDavid du Colombier 
73534e04225SDavid du Colombier 	for(i=0; i<m->nuser; i++){
73634e04225SDavid du Colombier 		free(m->user[i].name);
73734e04225SDavid du Colombier 		free(m->user[i].auth);
73834e04225SDavid du Colombier 	}
73934e04225SDavid du Colombier 	for(i=0; i<m->ngroup; i++)
74034e04225SDavid du Colombier 		free(m->group[i].name);
74134e04225SDavid du Colombier 	free(m->user);
74234e04225SDavid du Colombier 	free(m->group);
74334e04225SDavid du Colombier 	free(m->ubyid);
74434e04225SDavid du Colombier 	free(m->ubyname);
74534e04225SDavid du Colombier 	free(m->gbyid);
74634e04225SDavid du Colombier 	free(m->gbyname);
74734e04225SDavid du Colombier 	free(m);
74834e04225SDavid du Colombier }
74934e04225SDavid du Colombier 
75034e04225SDavid du Colombier Map*
readmap(char * passwd,char * group)75134e04225SDavid du Colombier readmap(char *passwd, char *group)
75234e04225SDavid du Colombier {
75334e04225SDavid du Colombier 	char *s, *f[10], *p, *nextp, *name;
75434e04225SDavid du Colombier 	uchar *q, *eq;
75534e04225SDavid du Colombier 	int i, n, nf, line, uid, gid;
75634e04225SDavid du Colombier 	Biobuf *b;
75734e04225SDavid du Colombier 	Map *m;
75834e04225SDavid du Colombier 	User *u;
75934e04225SDavid du Colombier 	Group *g;
76034e04225SDavid du Colombier 	SunAuthUnix au;
76134e04225SDavid du Colombier 
76234e04225SDavid du Colombier 	m = emalloc(sizeof(Map));
76334e04225SDavid du Colombier 
76434e04225SDavid du Colombier 	if((b = Bopen(passwd, OREAD)) == nil){
76534e04225SDavid du Colombier 		free(m);
76634e04225SDavid du Colombier 		return nil;
76734e04225SDavid du Colombier 	}
76834e04225SDavid du Colombier 	line = 0;
76934e04225SDavid du Colombier 	for(; (s = Brdstr(b, '\n', 1)) != nil; free(s)){
77034e04225SDavid du Colombier 		line++;
77134e04225SDavid du Colombier 		if(s[0] == '#')
77234e04225SDavid du Colombier 			continue;
77334e04225SDavid du Colombier 		nf = getfields(s, f, nelem(f), 0, ":");
77434e04225SDavid du Colombier 		if(nf < 4)
77534e04225SDavid du Colombier 			continue;
77634e04225SDavid du Colombier 		name = f[0];
77734e04225SDavid du Colombier 		uid = strtol(f[2], &p, 10);
77834e04225SDavid du Colombier 		if(f[2][0] == 0 || *p != 0){
77934e04225SDavid du Colombier 			fprint(2, "%s:%d: non-numeric id in third field\n", passwd, line);
78034e04225SDavid du Colombier 			continue;
78134e04225SDavid du Colombier 		}
78234e04225SDavid du Colombier 		gid = strtol(f[3], &p, 10);
78334e04225SDavid du Colombier 		if(f[3][0] == 0 || *p != 0){
78434e04225SDavid du Colombier 			fprint(2, "%s:%d: non-numeric id in fourth field\n", passwd, line);
78534e04225SDavid du Colombier 			continue;
78634e04225SDavid du Colombier 		}
78734e04225SDavid du Colombier 		if(m->nuser%32 == 0)
78834e04225SDavid du Colombier 			m->user = erealloc(m->user, (m->nuser+32)*sizeof(m->user[0]));
78934e04225SDavid du Colombier 		u = &m->user[m->nuser++];
79034e04225SDavid du Colombier 		u->name = estrdup9p(name);
79134e04225SDavid du Colombier 		u->uid = uid;
79234e04225SDavid du Colombier 		u->gid = gid;
79334e04225SDavid du Colombier 		u->ng = 0;
79434e04225SDavid du Colombier 		u->auth = 0;
79534e04225SDavid du Colombier 		u->nauth = 0;
79634e04225SDavid du Colombier 	}
79734e04225SDavid du Colombier 	Bterm(b);
79834e04225SDavid du Colombier 	m->ubyname = emalloc(m->nuser*sizeof(User*));
79934e04225SDavid du Colombier 	m->ubyid = emalloc(m->nuser*sizeof(User*));
80034e04225SDavid du Colombier 	for(i=0; i<m->nuser; i++){
80134e04225SDavid du Colombier 		m->ubyname[i] = &m->user[i];
80234e04225SDavid du Colombier 		m->ubyid[i] = &m->user[i];
80334e04225SDavid du Colombier 	}
80434e04225SDavid du Colombier 	qsort(m->ubyname, m->nuser, sizeof(m->ubyname[0]), namecmp);
80534e04225SDavid du Colombier 	qsort(m->ubyid, m->nuser, sizeof(m->ubyid[0]), idcmp);
80634e04225SDavid du Colombier 
80734e04225SDavid du Colombier 	if((b = Bopen(group, OREAD)) == nil){
80834e04225SDavid du Colombier 		closemap(m);
80934e04225SDavid du Colombier 		return nil;
81034e04225SDavid du Colombier 	}
81134e04225SDavid du Colombier 	line = 0;
81234e04225SDavid du Colombier 	for(; (s = Brdstr(b, '\n', 1)) != nil; free(s)){
81334e04225SDavid du Colombier 		line++;
81434e04225SDavid du Colombier 		if(s[0] == '#')
81534e04225SDavid du Colombier 			continue;
81634e04225SDavid du Colombier 		nf = getfields(s, f, nelem(f), 0, ":");
81734e04225SDavid du Colombier 		if(nf < 4)
81834e04225SDavid du Colombier 			continue;
81934e04225SDavid du Colombier 		name = f[0];
82034e04225SDavid du Colombier 		gid = strtol(f[2], &p, 10);
82134e04225SDavid du Colombier 		if(f[2][0] == 0 || *p != 0){
82234e04225SDavid du Colombier 			fprint(2, "%s:%d: non-numeric id in third field\n", group, line);
82334e04225SDavid du Colombier 			continue;
82434e04225SDavid du Colombier 		}
82534e04225SDavid du Colombier 		if(m->ngroup%32 == 0)
82634e04225SDavid du Colombier 			m->group = erealloc(m->group, (m->ngroup+32)*sizeof(m->group[0]));
82734e04225SDavid du Colombier 		g = &m->group[m->ngroup++];
82834e04225SDavid du Colombier 		g->name = estrdup9p(name);
82934e04225SDavid du Colombier 		g->gid = gid;
83034e04225SDavid du Colombier 
83134e04225SDavid du Colombier 		for(p=f[3]; *p; p=nextp){
83234e04225SDavid du Colombier 			if((nextp = strchr(p, ',')) != nil)
83334e04225SDavid du Colombier 				*nextp++ = 0;
83434e04225SDavid du Colombier 			else
83534e04225SDavid du Colombier 				nextp = p+strlen(p);
83634e04225SDavid du Colombier 			u = finduser(m->ubyname, m->nuser, p);
83734e04225SDavid du Colombier 			if(u == nil){
83834e04225SDavid du Colombier 				if(verbose)
83934e04225SDavid du Colombier 					fprint(2, "%s:%d: unknown user %s\n", group, line, p);
84034e04225SDavid du Colombier 				continue;
84134e04225SDavid du Colombier 			}
84234e04225SDavid du Colombier 			if(u->ng >= nelem(u->g)){
84334e04225SDavid du Colombier 				fprint(2, "%s:%d: user %s is in too many groups; ignoring %s\n", group, line, p, name);
84434e04225SDavid du Colombier 				continue;
84534e04225SDavid du Colombier 			}
84634e04225SDavid du Colombier 			u->g[u->ng++] = gid;
84734e04225SDavid du Colombier 		}
84834e04225SDavid du Colombier 	}
84934e04225SDavid du Colombier 	Bterm(b);
85034e04225SDavid du Colombier 	m->gbyname = emalloc(m->ngroup*sizeof(Group*));
85134e04225SDavid du Colombier 	m->gbyid = emalloc(m->ngroup*sizeof(Group*));
85234e04225SDavid du Colombier 	for(i=0; i<m->ngroup; i++){
85334e04225SDavid du Colombier 		m->gbyname[i] = &m->group[i];
85434e04225SDavid du Colombier 		m->gbyid[i] = &m->group[i];
85534e04225SDavid du Colombier 	}
85634e04225SDavid du Colombier 	qsort(m->gbyname, m->ngroup, sizeof(m->gbyname[0]), namecmp);
85734e04225SDavid du Colombier 	qsort(m->gbyid, m->ngroup, sizeof(m->gbyid[0]), idcmp);
85834e04225SDavid du Colombier 
85934e04225SDavid du Colombier 	for(i=0; i<m->nuser; i++){
86034e04225SDavid du Colombier 		au.stamp = 0;
86134e04225SDavid du Colombier 		au.sysname = sys;
86234e04225SDavid du Colombier 		au.uid = m->user[i].uid;
86334e04225SDavid du Colombier 		au.gid = m->user[i].gid;
86434e04225SDavid du Colombier 		memmove(au.g, m->user[i].g, sizeof au.g);
86534e04225SDavid du Colombier 		au.ng = m->user[i].ng;
86634e04225SDavid du Colombier 		n = sunAuthUnixSize(&au);
86734e04225SDavid du Colombier 		q = emalloc(n);
86834e04225SDavid du Colombier 		eq = q+n;
86934e04225SDavid du Colombier 		m->user[i].auth = q;
87034e04225SDavid du Colombier 		m->user[i].nauth = n;
87134e04225SDavid du Colombier 		if(sunAuthUnixPack(q, eq, &q, &au) < 0 || q != eq){
87234e04225SDavid du Colombier 			fprint(2, "sunAuthUnixPack failed for %s\n", m->user[i].name);
87334e04225SDavid du Colombier 			free(m->user[i].auth);
87434e04225SDavid du Colombier 			m->user[i].auth = 0;
87534e04225SDavid du Colombier 			m->user[i].nauth = 0;
87634e04225SDavid du Colombier 		}
87734e04225SDavid du Colombier 	}
87834e04225SDavid du Colombier 
87934e04225SDavid du Colombier 	return m;
88034e04225SDavid du Colombier }
88134e04225SDavid du Colombier 
88234e04225SDavid du Colombier Auth*
mkauth(char * user)88334e04225SDavid du Colombier mkauth(char *user)
88434e04225SDavid du Colombier {
88534e04225SDavid du Colombier 	Auth *a;
88634e04225SDavid du Colombier 	uchar *p;
88734e04225SDavid du Colombier 	int n;
88834e04225SDavid du Colombier 	SunAuthUnix au;
88934e04225SDavid du Colombier 	User *u;
89034e04225SDavid du Colombier 
89134e04225SDavid du Colombier 	u = finduser(map->ubyname, map->nuser, user);
89234e04225SDavid du Colombier 	if(u == nil || u->nauth == 0){
89334e04225SDavid du Colombier 		/* nobody */
89434e04225SDavid du Colombier 		au.stamp = 0;
89534e04225SDavid du Colombier 		au.uid = -1;
89634e04225SDavid du Colombier 		au.gid = -1;
89734e04225SDavid du Colombier 		au.ng = 0;
89834e04225SDavid du Colombier 		au.sysname = sys;
89934e04225SDavid du Colombier 		n = sunAuthUnixSize(&au);
90034e04225SDavid du Colombier 		a = emalloc(sizeof(Auth)+n);
90134e04225SDavid du Colombier 		a->data = (uchar*)&a[1];
90234e04225SDavid du Colombier 		a->ndata = n;
90334e04225SDavid du Colombier 		if(sunAuthUnixPack(a->data, a->data+a->ndata, &p, &au) < 0
90434e04225SDavid du Colombier 		|| p != a->data+a->ndata){
90534e04225SDavid du Colombier 			free(a);
90634e04225SDavid du Colombier 			return nil;
90734e04225SDavid du Colombier 		}
90834e04225SDavid du Colombier 		a->ref = 1;
90934e04225SDavid du Colombier if(verbose)print("creds for %s: %.*H\n", user, a->ndata, a->data);
91034e04225SDavid du Colombier 		return a;
91134e04225SDavid du Colombier 	}
91234e04225SDavid du Colombier 
91334e04225SDavid du Colombier 	a = emalloc(sizeof(Auth)+u->nauth);
91434e04225SDavid du Colombier 	a->data = (uchar*)&a[1];
91534e04225SDavid du Colombier 	a->ndata = u->nauth;
91634e04225SDavid du Colombier 	memmove(a->data, u->auth, a->ndata);
91734e04225SDavid du Colombier 	a->ref = 1;
91834e04225SDavid du Colombier if(verbose)print("creds for %s: %.*H\n", user, a->ndata, a->data);
91934e04225SDavid du Colombier 	return a;
92034e04225SDavid du Colombier }
92134e04225SDavid du Colombier 
92234e04225SDavid du Colombier void
freeauth(Auth * a)92334e04225SDavid du Colombier freeauth(Auth *a)
92434e04225SDavid du Colombier {
92534e04225SDavid du Colombier 	if(--a->ref > 0)
92634e04225SDavid du Colombier 		return;
92734e04225SDavid du Colombier 	free(a);
92834e04225SDavid du Colombier }
92934e04225SDavid du Colombier 
93034e04225SDavid du Colombier /*
93134e04225SDavid du Colombier  * 9P server
93234e04225SDavid du Colombier  */
93334e04225SDavid du Colombier void
responderrstr(Req * r)93434e04225SDavid du Colombier responderrstr(Req *r)
93534e04225SDavid du Colombier {
93634e04225SDavid du Colombier 	char e[ERRMAX];
93734e04225SDavid du Colombier 
93834e04225SDavid du Colombier 	rerrstr(e, sizeof e);
93934e04225SDavid du Colombier 	respond(r, e);
94034e04225SDavid du Colombier }
94134e04225SDavid du Colombier 
94234e04225SDavid du Colombier void
fsdestroyfid(Fid * fid)94334e04225SDavid du Colombier fsdestroyfid(Fid *fid)
94434e04225SDavid du Colombier {
94534e04225SDavid du Colombier 	FidAux *aux;
94634e04225SDavid du Colombier 
94734e04225SDavid du Colombier 	aux = fid->aux;
94834e04225SDavid du Colombier 	if(aux == nil)
94934e04225SDavid du Colombier 		return;
95034e04225SDavid du Colombier 	freeauth(aux->auth);
95134e04225SDavid du Colombier 	free(aux->name);
95234e04225SDavid du Colombier 	free(aux);
95334e04225SDavid du Colombier }
95434e04225SDavid du Colombier 
95534e04225SDavid du Colombier void
attrToQid(Nfs3Attr * attr,Qid * qid)95634e04225SDavid du Colombier attrToQid(Nfs3Attr *attr, Qid *qid)
95734e04225SDavid du Colombier {
95834e04225SDavid du Colombier 	qid->path = attr->fileid;
95934e04225SDavid du Colombier 	qid->vers = attr->mtime.sec;
96034e04225SDavid du Colombier 	qid->type = 0;
96134e04225SDavid du Colombier 	if(attr->type == Nfs3FileDir)
96234e04225SDavid du Colombier 		qid->type |= QTDIR;
96334e04225SDavid du Colombier }
96434e04225SDavid du Colombier 
96534e04225SDavid du Colombier void
attrToDir(Nfs3Attr * attr,Dir * d)96634e04225SDavid du Colombier attrToDir(Nfs3Attr *attr, Dir *d)
96734e04225SDavid du Colombier {
96834e04225SDavid du Colombier 	d->mode = attr->mode & 0777;
96934e04225SDavid du Colombier 	if(attr->type == Nfs3FileDir)
97034e04225SDavid du Colombier 		d->mode |= DMDIR;
97134e04225SDavid du Colombier 	d->uid = uidtostr(attr->uid);
97234e04225SDavid du Colombier 	d->gid = gidtostr(attr->gid);
97334e04225SDavid du Colombier 	d->length = attr->size;
97434e04225SDavid du Colombier 	attrToQid(attr, &d->qid);
97534e04225SDavid du Colombier 	d->mtime = attr->mtime.sec;
97634e04225SDavid du Colombier 	d->atime = attr->atime.sec;
97734e04225SDavid du Colombier 	d->muid = nil;
97834e04225SDavid du Colombier }
97934e04225SDavid du Colombier 
98034e04225SDavid du Colombier void
fsattach(Req * r)98134e04225SDavid du Colombier fsattach(Req *r)
98234e04225SDavid du Colombier {
98334e04225SDavid du Colombier 	char *path;
98434e04225SDavid du Colombier 	Auth *auth;
98534e04225SDavid du Colombier 	FidAux *aux;
98634e04225SDavid du Colombier 	Nfs3Attr attr;
98734e04225SDavid du Colombier 	Nfs3Handle h;
98834e04225SDavid du Colombier 
98934e04225SDavid du Colombier 	path = r->ifcall.aname;
99034e04225SDavid du Colombier 	if(path==nil || path[0]==0)
99134e04225SDavid du Colombier 		path = defaultpath;
99234e04225SDavid du Colombier 
99334e04225SDavid du Colombier 	auth = mkauth(r->ifcall.uname);
99434e04225SDavid du Colombier 
99534e04225SDavid du Colombier 	if(mountMnt(auth, r->tag, path, &h) < 0
99634e04225SDavid du Colombier 	|| nfsGetattr(auth, r->tag, &h, &attr) < 0){
99734e04225SDavid du Colombier 		freeauth(auth);
99834e04225SDavid du Colombier 		responderrstr(r);
99934e04225SDavid du Colombier 		return;
100034e04225SDavid du Colombier 	}
100134e04225SDavid du Colombier 
100234e04225SDavid du Colombier 	aux = emalloc(sizeof(FidAux));
100334e04225SDavid du Colombier 	aux->auth = auth;
100434e04225SDavid du Colombier 	aux->handle = h;
100534e04225SDavid du Colombier 	aux->cookie = 0;
100634e04225SDavid du Colombier 	aux->name = nil;
100734e04225SDavid du Colombier 	memset(&aux->parent, 0, sizeof aux->parent);
100834e04225SDavid du Colombier 	r->fid->aux = aux;
100934e04225SDavid du Colombier 	attrToQid(&attr, &r->fid->qid);
101034e04225SDavid du Colombier 	r->ofcall.qid = r->fid->qid;
101134e04225SDavid du Colombier 	respond(r, nil);
101234e04225SDavid du Colombier }
101334e04225SDavid du Colombier 
101434e04225SDavid du Colombier void
fsopen(Req * r)101534e04225SDavid du Colombier fsopen(Req *r)
101634e04225SDavid du Colombier {
101734e04225SDavid du Colombier 	FidAux *aux;
101834e04225SDavid du Colombier 	Nfs3Attr attr;
10192b5f567bSDavid du Colombier 	Nfs3SetAttr sa;
102034e04225SDavid du Colombier 	u1int have;
102134e04225SDavid du Colombier 	ulong a, b;
102234e04225SDavid du Colombier 
102334e04225SDavid du Colombier 	aux = r->fid->aux;
102434e04225SDavid du Colombier 	a = 0;
102534e04225SDavid du Colombier 	switch(r->ifcall.mode&OMASK){
102634e04225SDavid du Colombier 	case OREAD:
10272b5f567bSDavid du Colombier 		a = 0x0001;
102834e04225SDavid du Colombier 		break;
102934e04225SDavid du Colombier 	case OWRITE:
10302b5f567bSDavid du Colombier 		a = 0x0004;
103134e04225SDavid du Colombier 		break;
103234e04225SDavid du Colombier 	case ORDWR:
10332b5f567bSDavid du Colombier 		a = 0x0001|0x0004;
103434e04225SDavid du Colombier 		break;
103534e04225SDavid du Colombier 	case OEXEC:
103634e04225SDavid du Colombier 		a = 0x20;
103734e04225SDavid du Colombier 		break;
103834e04225SDavid du Colombier 	}
103934e04225SDavid du Colombier 	if(r->ifcall.mode&OTRUNC)
10402b5f567bSDavid du Colombier 		a |= 0x0004;
104134e04225SDavid du Colombier 
104234e04225SDavid du Colombier 	if(nfsAccess(aux->auth, r->tag, &aux->handle, a, &b, &have, &attr) < 0
104334e04225SDavid du Colombier 	|| (!have && nfsGetattr(aux->auth, r->tag, &aux->handle, &attr) < 0)){
10442b5f567bSDavid du Colombier     Error:
104534e04225SDavid du Colombier 		responderrstr(r);
104634e04225SDavid du Colombier 		return;
104734e04225SDavid du Colombier 	}
1048*f314cdf7SDavid du Colombier 	if(a != b){
1049*f314cdf7SDavid du Colombier 		respond(r, "permission denied");
1050*f314cdf7SDavid du Colombier 		return;
1051*f314cdf7SDavid du Colombier 	}
10522b5f567bSDavid du Colombier 	if(r->ifcall.mode&OTRUNC){
10532b5f567bSDavid du Colombier 		memset(&sa, 0, sizeof sa);
10542b5f567bSDavid du Colombier 		sa.setSize = 1;
10552b5f567bSDavid du Colombier 		if(nfsSetattr(aux->auth, r->tag, &aux->handle, &sa) < 0)
10562b5f567bSDavid du Colombier 			goto Error;
10572b5f567bSDavid du Colombier 	}
105834e04225SDavid du Colombier 	attrToQid(&attr, &r->fid->qid);
105934e04225SDavid du Colombier 	r->ofcall.qid = r->fid->qid;
106034e04225SDavid du Colombier 	respond(r, nil);
106134e04225SDavid du Colombier }
106234e04225SDavid du Colombier 
106334e04225SDavid du Colombier void
fscreate(Req * r)106434e04225SDavid du Colombier fscreate(Req *r)
106534e04225SDavid du Colombier {
106634e04225SDavid du Colombier 	FidAux *aux;
106734e04225SDavid du Colombier 	u1int have;
106834e04225SDavid du Colombier 	Nfs3Attr attr;
106934e04225SDavid du Colombier 	Nfs3Handle h;
107034e04225SDavid du Colombier 	ulong mode;
107134e04225SDavid du Colombier 	uint gid;
107234e04225SDavid du Colombier 	int (*mk)(Auth*, ulong, Nfs3Handle*, char*, Nfs3Handle*, ulong, uint, u1int*, Nfs3Attr*);
107334e04225SDavid du Colombier 
107434e04225SDavid du Colombier 	aux = r->fid->aux;
107534e04225SDavid du Colombier 
107634e04225SDavid du Colombier 	/*
107734e04225SDavid du Colombier 	 * Plan 9 has no umask, so let's use the
107834e04225SDavid du Colombier 	 * parent directory bits like Plan 9 does.
107934e04225SDavid du Colombier 	 * What the heck, let's inherit the group too.
108034e04225SDavid du Colombier 	 * (Unix will let us set the group to anything
108134e04225SDavid du Colombier 	 * since we're the owner!)
108234e04225SDavid du Colombier 	 */
108334e04225SDavid du Colombier 	if(nfsGetattr(aux->auth, r->tag, &aux->handle, &attr) < 0){
108434e04225SDavid du Colombier 		responderrstr(r);
108534e04225SDavid du Colombier 		return;
108634e04225SDavid du Colombier 	}
108734e04225SDavid du Colombier 	mode = r->ifcall.perm&0777;
108834e04225SDavid du Colombier 	if(r->ifcall.perm&DMDIR)
108934e04225SDavid du Colombier 		mode &= (attr.mode&0666) | ~0666;
109034e04225SDavid du Colombier 	else
109134e04225SDavid du Colombier 		mode &= (attr.mode&0777) | ~0777;
109234e04225SDavid du Colombier 	gid = attr.gid;
109334e04225SDavid du Colombier 
109434e04225SDavid du Colombier 	if(r->ifcall.perm&DMDIR)
109534e04225SDavid du Colombier 		mk = nfsMkdir;
109634e04225SDavid du Colombier 	else
109734e04225SDavid du Colombier 		mk = nfsCreate;
109834e04225SDavid du Colombier 
109934e04225SDavid du Colombier 	if((*mk)(aux->auth, r->tag, &aux->handle, r->ifcall.name, &h, mode, gid, &have, &attr) < 0
110034e04225SDavid du Colombier 	|| (!have && nfsGetattr(aux->auth, r->tag, &h, &attr) < 0)){
110134e04225SDavid du Colombier 		responderrstr(r);
110234e04225SDavid du Colombier 		return;
110334e04225SDavid du Colombier 	}
110434e04225SDavid du Colombier 	attrToQid(&attr, &r->fid->qid);
110534e04225SDavid du Colombier 	aux->parent = aux->handle;
110634e04225SDavid du Colombier 	aux->handle = h;
110734e04225SDavid du Colombier 	free(aux->name);
110834e04225SDavid du Colombier 	aux->name = estrdup9p(r->ifcall.name);
110934e04225SDavid du Colombier 	r->ofcall.qid = r->fid->qid;
111034e04225SDavid du Colombier 	respond(r, nil);
111134e04225SDavid du Colombier }
111234e04225SDavid du Colombier 
111334e04225SDavid du Colombier void
fsreaddir(Req * r)111434e04225SDavid du Colombier fsreaddir(Req *r)
111534e04225SDavid du Colombier {
111634e04225SDavid du Colombier 	FidAux *aux;
111734e04225SDavid du Colombier 	uchar *p, *freeme, *ep, *p9, *ep9;
1118fb7f0c93SDavid du Colombier 	char *s;
111934e04225SDavid du Colombier 	uint count;
112034e04225SDavid du Colombier 	int n, (*unpack)(uchar*, uchar*, uchar**, Nfs3Entry*);
112134e04225SDavid du Colombier 	Nfs3Entry e;
112234e04225SDavid du Colombier 	u64int cookie;
112334e04225SDavid du Colombier 	Dir d;
112434e04225SDavid du Colombier 
112534e04225SDavid du Colombier 	aux = r->fid->aux;
112634e04225SDavid du Colombier 	/*
112734e04225SDavid du Colombier 	 * r->ifcall.count seems a reasonable estimate to
112834e04225SDavid du Colombier 	 * how much NFS entry data we want.  is it?
112934e04225SDavid du Colombier 	 */
113034e04225SDavid du Colombier 	if(r->ifcall.offset)
113134e04225SDavid du Colombier 		cookie = aux->cookie;
113234e04225SDavid du Colombier 	else
113334e04225SDavid du Colombier 		cookie = 0;
113434e04225SDavid du Colombier 	if(nfsReadDir(aux->auth, r->tag, &aux->handle, r->ifcall.count, cookie,
113534e04225SDavid du Colombier 		&p, &count, &unpack, &freeme) < 0){
113634e04225SDavid du Colombier 		responderrstr(r);
113734e04225SDavid du Colombier 		return;
113834e04225SDavid du Colombier 	}
113934e04225SDavid du Colombier 	ep = p+count;
114034e04225SDavid du Colombier 
114134e04225SDavid du Colombier 	p9 = (uchar*)r->ofcall.data;
114234e04225SDavid du Colombier 	ep9 = p9+r->ifcall.count;
114334e04225SDavid du Colombier 
114434e04225SDavid du Colombier 	/*
114534e04225SDavid du Colombier 	 * BUG: Issue all of the stat requests in parallel.
114634e04225SDavid du Colombier 	 */
114734e04225SDavid du Colombier 	while(p < ep && p9 < ep9){
114834e04225SDavid du Colombier 		if((*unpack)(p, ep, &p, &e) < 0)
114934e04225SDavid du Colombier 			break;
115034e04225SDavid du Colombier 		aux->cookie = e.cookie;
115134e04225SDavid du Colombier 		if(strcmp(e.name, ".") == 0 || strcmp(e.name, "..") == 0)
115234e04225SDavid du Colombier 			continue;
1153fb7f0c93SDavid du Colombier 		for(s=e.name; (uchar)*s >= ' '; s++)
1154fb7f0c93SDavid du Colombier 			;
1155fb7f0c93SDavid du Colombier 		if(*s != 0)	/* bad character in name */
1156fb7f0c93SDavid du Colombier 			continue;
115734e04225SDavid du Colombier 		if(!e.haveAttr && !e.haveHandle)
115834e04225SDavid du Colombier 			if(nfsLookup(aux->auth, r->tag, &aux->handle, e.name, &e.handle, &e.haveAttr, &e.attr) < 0)
115934e04225SDavid du Colombier 				continue;
116034e04225SDavid du Colombier 		if(!e.haveAttr)
116134e04225SDavid du Colombier 			if(nfsGetattr(aux->auth, r->tag, &e.handle, &e.attr) < 0)
116234e04225SDavid du Colombier 				continue;
116334e04225SDavid du Colombier 		memset(&d, 0, sizeof d);
116434e04225SDavid du Colombier 		attrToDir(&e.attr, &d);
116534e04225SDavid du Colombier 		d.name = e.name;
116634e04225SDavid du Colombier 		if((n = convD2M(&d, p9, ep9-p9)) <= BIT16SZ)
116734e04225SDavid du Colombier 			break;
116834e04225SDavid du Colombier 		p9 += n;
116934e04225SDavid du Colombier 	}
117034e04225SDavid du Colombier 	free(freeme);
117134e04225SDavid du Colombier 	r->ofcall.count = p9 - (uchar*)r->ofcall.data;
117234e04225SDavid du Colombier 	respond(r, nil);
117334e04225SDavid du Colombier }
117434e04225SDavid du Colombier 
117534e04225SDavid du Colombier void
fsread(Req * r)117634e04225SDavid du Colombier fsread(Req *r)
117734e04225SDavid du Colombier {
117834e04225SDavid du Colombier 	uchar *p, *freeme;
117934e04225SDavid du Colombier 	uint count;
118034e04225SDavid du Colombier 	FidAux *aux;
118134e04225SDavid du Colombier 
118234e04225SDavid du Colombier 	if(r->fid->qid.type&QTDIR){
118334e04225SDavid du Colombier 		fsreaddir(r);
118434e04225SDavid du Colombier 		return;
118534e04225SDavid du Colombier 	}
118634e04225SDavid du Colombier 
118734e04225SDavid du Colombier 	aux = r->fid->aux;
118834e04225SDavid du Colombier 	if(nfsRead(aux->auth, r->tag, &aux->handle, r->ifcall.count, r->ifcall.offset, &p, &count, &freeme) < 0){
118934e04225SDavid du Colombier 		responderrstr(r);
119034e04225SDavid du Colombier 		return;
119134e04225SDavid du Colombier 	}
119234e04225SDavid du Colombier 	r->ofcall.data = (char*)p;
119334e04225SDavid du Colombier 	r->ofcall.count = count;
119434e04225SDavid du Colombier 	respond(r, nil);
119534e04225SDavid du Colombier 	free(freeme);
119634e04225SDavid du Colombier }
119734e04225SDavid du Colombier 
119834e04225SDavid du Colombier void
fswrite(Req * r)119934e04225SDavid du Colombier fswrite(Req *r)
120034e04225SDavid du Colombier {
120134e04225SDavid du Colombier 	uint count;
120234e04225SDavid du Colombier 	FidAux *aux;
120334e04225SDavid du Colombier 
120434e04225SDavid du Colombier 	aux = r->fid->aux;
120534e04225SDavid du Colombier 	if(nfsWrite(aux->auth, r->tag, &aux->handle, (uchar*)r->ifcall.data, r->ifcall.count, r->ifcall.offset, &count) < 0){
120634e04225SDavid du Colombier 		responderrstr(r);
120734e04225SDavid du Colombier 		return;
120834e04225SDavid du Colombier 	}
120934e04225SDavid du Colombier 	r->ofcall.count = count;
121034e04225SDavid du Colombier 	respond(r, nil);
121134e04225SDavid du Colombier }
121234e04225SDavid du Colombier 
121334e04225SDavid du Colombier void
fsremove(Req * r)121434e04225SDavid du Colombier fsremove(Req *r)
121534e04225SDavid du Colombier {
121634e04225SDavid du Colombier 	int n;
121734e04225SDavid du Colombier 	FidAux *aux;
121834e04225SDavid du Colombier 
121934e04225SDavid du Colombier 	aux = r->fid->aux;
122034e04225SDavid du Colombier 	if(aux->name == nil){
122134e04225SDavid du Colombier 		respond(r, "nfs3client botch -- don't know parent handle in remove");
122234e04225SDavid du Colombier 		return;
122334e04225SDavid du Colombier 	}
122434e04225SDavid du Colombier 	if(r->fid->qid.type&QTDIR)
122534e04225SDavid du Colombier 		n = nfsRmdir(aux->auth, r->tag, &aux->parent, aux->name);
122634e04225SDavid du Colombier 	else
122734e04225SDavid du Colombier 		n = nfsRemove(aux->auth, r->tag, &aux->parent, aux->name);
122834e04225SDavid du Colombier 	if(n < 0){
122934e04225SDavid du Colombier 		responderrstr(r);
123034e04225SDavid du Colombier 		return;
123134e04225SDavid du Colombier 	}
123234e04225SDavid du Colombier 	respond(r, nil);
123334e04225SDavid du Colombier }
123434e04225SDavid du Colombier 
123534e04225SDavid du Colombier void
fsstat(Req * r)123634e04225SDavid du Colombier fsstat(Req *r)
123734e04225SDavid du Colombier {
123834e04225SDavid du Colombier 	FidAux *aux;
123934e04225SDavid du Colombier 	Nfs3Attr attr;
124034e04225SDavid du Colombier 
124134e04225SDavid du Colombier 	aux = r->fid->aux;
124234e04225SDavid du Colombier 	if(nfsGetattr(aux->auth, r->tag, &aux->handle, &attr) < 0){
124334e04225SDavid du Colombier 		responderrstr(r);
124434e04225SDavid du Colombier 		return;
124534e04225SDavid du Colombier 	}
124634e04225SDavid du Colombier 	memset(&r->d, 0, sizeof r->d);
124734e04225SDavid du Colombier 	attrToDir(&attr, &r->d);
124834e04225SDavid du Colombier 	r->d.name = estrdup9p(aux->name ? aux->name : "???");
124934e04225SDavid du Colombier 	respond(r, nil);
125034e04225SDavid du Colombier }
125134e04225SDavid du Colombier 
125234e04225SDavid du Colombier void
fswstat(Req * r)125334e04225SDavid du Colombier fswstat(Req *r)
125434e04225SDavid du Colombier {
125534e04225SDavid du Colombier 	int op, sync;
125634e04225SDavid du Colombier 	FidAux *aux;
125734e04225SDavid du Colombier 	Nfs3SetAttr attr;
125834e04225SDavid du Colombier 
1259fb7f0c93SDavid du Colombier 	memset(&attr, 0, sizeof attr);
126034e04225SDavid du Colombier 	aux = r->fid->aux;
126134e04225SDavid du Colombier 
126234e04225SDavid du Colombier 	/* Fill out stat first to catch errors */
126334e04225SDavid du Colombier 	op = 0;
126434e04225SDavid du Colombier 	sync = 1;
126534e04225SDavid du Colombier 	if(~r->d.mode){
126634e04225SDavid du Colombier 		if(r->d.mode&(DMAPPEND|DMEXCL)){
126734e04225SDavid du Colombier 			respond(r, "wstat -- DMAPPEND and DMEXCL bits not supported");
126834e04225SDavid du Colombier 			return;
126934e04225SDavid du Colombier 		}
127034e04225SDavid du Colombier 		op = 1;
127134e04225SDavid du Colombier 		sync = 0;
127234e04225SDavid du Colombier 		attr.setMode = 1;
127334e04225SDavid du Colombier 		attr.mode = r->d.mode & 0777;
127434e04225SDavid du Colombier 	}
127534e04225SDavid du Colombier 	if(r->d.uid && r->d.uid[0]){
127634e04225SDavid du Colombier 		attr.setUid = 1;
127734e04225SDavid du Colombier 		if(strtouid(r->d.uid, &attr.uid) < 0){
127834e04225SDavid du Colombier 			respond(r, "wstat -- unknown uid");
127934e04225SDavid du Colombier 			return;
128034e04225SDavid du Colombier 		}
128134e04225SDavid du Colombier 		op = 1;
128234e04225SDavid du Colombier 		sync = 0;
128334e04225SDavid du Colombier 	}
128434e04225SDavid du Colombier 	if(r->d.gid && r->d.gid[0]){
128534e04225SDavid du Colombier 		attr.setGid = 1;
128634e04225SDavid du Colombier 		if(strtogid(r->d.gid, &attr.gid) < 0){
128734e04225SDavid du Colombier 			respond(r, "wstat -- unknown gid");
128834e04225SDavid du Colombier 			return;
128934e04225SDavid du Colombier 		}
129034e04225SDavid du Colombier 		op = 1;
129134e04225SDavid du Colombier 		sync = 0;
129234e04225SDavid du Colombier 	}
129334e04225SDavid du Colombier 	if(~r->d.length){
129434e04225SDavid du Colombier 		attr.setSize = 1;
129534e04225SDavid du Colombier 		attr.size = r->d.length;
1296fb7f0c93SDavid du Colombier 		op = 1;
1297fb7f0c93SDavid du Colombier 		sync = 0;
129834e04225SDavid du Colombier 	}
129934e04225SDavid du Colombier 	if(~r->d.mtime){
1300fb7f0c93SDavid du Colombier 		attr.setMtime = Nfs3SetTimeClient;
130134e04225SDavid du Colombier 		attr.mtime.sec = r->d.mtime;
1302fb7f0c93SDavid du Colombier 		op = 1;
1303fb7f0c93SDavid du Colombier 		sync = 0;
1304fb7f0c93SDavid du Colombier 	}
1305fb7f0c93SDavid du Colombier 	if(~r->d.atime){
1306fb7f0c93SDavid du Colombier 		attr.setAtime = Nfs3SetTimeClient;
1307fb7f0c93SDavid du Colombier 		attr.atime.sec = r->d.atime;
1308fb7f0c93SDavid du Colombier 		op = 1;
1309fb7f0c93SDavid du Colombier 		sync = 0;
131034e04225SDavid du Colombier 	}
131134e04225SDavid du Colombier 
131234e04225SDavid du Colombier 	/* Try rename first because it's more likely to fail (?) */
131334e04225SDavid du Colombier 	if(r->d.name && r->d.name[0]){
131434e04225SDavid du Colombier 		if(aux->name == nil){
131534e04225SDavid du Colombier 			respond(r, "nfsclient botch -- don't know parent handle in rename");
131634e04225SDavid du Colombier 			return;
131734e04225SDavid du Colombier 		}
131834e04225SDavid du Colombier 		if(nfsRename(aux->auth, r->tag, &aux->parent, aux->name, &aux->parent, r->d.name) < 0){
131934e04225SDavid du Colombier 			responderrstr(r);
132034e04225SDavid du Colombier 			return;
132134e04225SDavid du Colombier 		}
132234e04225SDavid du Colombier 		free(aux->name);
132334e04225SDavid du Colombier 		aux->name = estrdup9p(r->d.name);
132434e04225SDavid du Colombier 		sync = 0;
132534e04225SDavid du Colombier 	}
132634e04225SDavid du Colombier 
132734e04225SDavid du Colombier 	/*
132834e04225SDavid du Colombier 	 * Now we have a problem.  The rename succeeded
132934e04225SDavid du Colombier 	 * but the setattr could fail.  Sic transit atomicity.
133034e04225SDavid du Colombier 	 */
133134e04225SDavid du Colombier 	if(op){
133234e04225SDavid du Colombier 		if(nfsSetattr(aux->auth, r->tag, &aux->handle, &attr) < 0){
133334e04225SDavid du Colombier 			responderrstr(r);
133434e04225SDavid du Colombier 			return;
133534e04225SDavid du Colombier 		}
133634e04225SDavid du Colombier 	}
133734e04225SDavid du Colombier 
133834e04225SDavid du Colombier 	if(sync){
133934e04225SDavid du Colombier 		/* NFS commit */
134034e04225SDavid du Colombier 		if(nfsCommit(aux->auth, r->tag, &aux->handle) < 0){
134134e04225SDavid du Colombier 			responderrstr(r);
134234e04225SDavid du Colombier 			return;
134334e04225SDavid du Colombier 		}
134434e04225SDavid du Colombier 	}
134534e04225SDavid du Colombier 
134634e04225SDavid du Colombier 	respond(r, nil);
134734e04225SDavid du Colombier }
134834e04225SDavid du Colombier 
134934e04225SDavid du Colombier char*
fswalk1(Fid * fid,char * name,void * v)135034e04225SDavid du Colombier fswalk1(Fid *fid, char *name, void *v)
135134e04225SDavid du Colombier {
135234e04225SDavid du Colombier 	u1int have;
135334e04225SDavid du Colombier 	ulong tag;
135434e04225SDavid du Colombier 	FidAux *aux;
135534e04225SDavid du Colombier 	Nfs3Attr attr;
135634e04225SDavid du Colombier 	Nfs3Handle h;
135734e04225SDavid du Colombier 
135834e04225SDavid du Colombier 	tag = *(ulong*)v;
135934e04225SDavid du Colombier 	aux = fid->aux;
136034e04225SDavid du Colombier 
136134e04225SDavid du Colombier 	if(nfsLookup(aux->auth, tag, &aux->handle, name, &h, &have, &attr) < 0
136234e04225SDavid du Colombier 	|| (!have && nfsGetattr(aux->auth, tag, &h, &attr) < 0)){
136334e04225SDavid du Colombier 		rerrstr(aux->err, sizeof aux->err);
136434e04225SDavid du Colombier 		return aux->err;
136534e04225SDavid du Colombier 	}
136634e04225SDavid du Colombier 
136734e04225SDavid du Colombier 	aux->parent = aux->handle;
136834e04225SDavid du Colombier 	aux->handle = h;
136934e04225SDavid du Colombier 	free(aux->name);
137034e04225SDavid du Colombier 	if(strcmp(name, "..") == 0)
137134e04225SDavid du Colombier 		aux->name = nil;
137234e04225SDavid du Colombier 	else
137334e04225SDavid du Colombier 		aux->name = estrdup9p(name);
137434e04225SDavid du Colombier 	attrToQid(&attr, &fid->qid);
137534e04225SDavid du Colombier 	return nil;
137634e04225SDavid du Colombier }
137734e04225SDavid du Colombier 
137834e04225SDavid du Colombier char*
fsclone(Fid * fid,Fid * newfid,void *)137934e04225SDavid du Colombier fsclone(Fid *fid, Fid *newfid, void*)
138034e04225SDavid du Colombier {
138134e04225SDavid du Colombier 	FidAux *a, *na;
138234e04225SDavid du Colombier 
138334e04225SDavid du Colombier 	a = fid->aux;
138434e04225SDavid du Colombier 	na = emalloc9p(sizeof(FidAux));
138534e04225SDavid du Colombier 	*na = *a;
138634e04225SDavid du Colombier 	if(na->name)
138734e04225SDavid du Colombier 		na->name = estrdup9p(na->name);
138834e04225SDavid du Colombier 	newfid->aux = na;
138934e04225SDavid du Colombier 	if(na->auth)
139034e04225SDavid du Colombier 		na->auth->ref++;
139134e04225SDavid du Colombier 	return nil;
139234e04225SDavid du Colombier }
139334e04225SDavid du Colombier 
139434e04225SDavid du Colombier void
fswalk(Req * r)139534e04225SDavid du Colombier fswalk(Req *r)
139634e04225SDavid du Colombier {
139734e04225SDavid du Colombier 	walkandclone(r, fswalk1, fsclone, &r->tag);
139834e04225SDavid du Colombier }
139934e04225SDavid du Colombier 
140034e04225SDavid du Colombier void
fsflush(Req * r)140134e04225SDavid du Colombier fsflush(Req *r)
140234e04225SDavid du Colombier {
140334e04225SDavid du Colombier 	Req *or;
140434e04225SDavid du Colombier 
140534e04225SDavid du Colombier 	/*
140634e04225SDavid du Colombier 	 * Send on the flush channel(s).
140734e04225SDavid du Colombier 	 * The library will make sure the response
140834e04225SDavid du Colombier 	 * is delayed as necessary.
140934e04225SDavid du Colombier 	 */
141034e04225SDavid du Colombier 	or = r->oldreq;
141134e04225SDavid du Colombier 	if(nfscli)
141234e04225SDavid du Colombier 		sendul(nfscli->flushchan, (ulong)or->tag);
141334e04225SDavid du Colombier 	if(mntcli)
141434e04225SDavid du Colombier 		sendul(mntcli->flushchan, (ulong)or->tag);
141534e04225SDavid du Colombier 	respond(r, nil);
141634e04225SDavid du Colombier }
141734e04225SDavid du Colombier 
141834e04225SDavid du Colombier void
fsdispatch(void * v)141934e04225SDavid du Colombier fsdispatch(void *v)
142034e04225SDavid du Colombier {
142134e04225SDavid du Colombier 	Req *r;
142234e04225SDavid du Colombier 
142334e04225SDavid du Colombier 	r = v;
142434e04225SDavid du Colombier 	switch(r->ifcall.type){
142534e04225SDavid du Colombier 	default:	respond(r, "unknown type");	break;
142634e04225SDavid du Colombier 	case Tattach:	fsattach(r);	break;
142734e04225SDavid du Colombier 	case Topen:	fsopen(r);	break;
142834e04225SDavid du Colombier 	case Tcreate:	fscreate(r);	break;
142934e04225SDavid du Colombier 	case Tread:	fsread(r);	break;
143034e04225SDavid du Colombier 	case Twrite:	fswrite(r);	break;
143134e04225SDavid du Colombier 	case Tremove:	fsremove(r);	break;
143234e04225SDavid du Colombier 	case Tflush:	fsflush(r);	break;
143334e04225SDavid du Colombier 	case Tstat:	fsstat(r);	break;
143434e04225SDavid du Colombier 	case Twstat:	fswstat(r);	break;
143534e04225SDavid du Colombier 	case Twalk:	fswalk(r);	break;
143634e04225SDavid du Colombier 	}
143734e04225SDavid du Colombier }
143834e04225SDavid du Colombier 
143934e04225SDavid du Colombier void
fsthread(void *)144034e04225SDavid du Colombier fsthread(void*)
144134e04225SDavid du Colombier {
144234e04225SDavid du Colombier 	Req *r;
144334e04225SDavid du Colombier 
144434e04225SDavid du Colombier 	while((r = recvp(fschan)) != nil)
144534e04225SDavid du Colombier 		threadcreate(fsdispatch, r, SunStackSize);
144634e04225SDavid du Colombier }
144734e04225SDavid du Colombier 
144834e04225SDavid du Colombier void
fssend(Req * r)144934e04225SDavid du Colombier fssend(Req *r)
145034e04225SDavid du Colombier {
145134e04225SDavid du Colombier 	sendp(fschan, r);
145234e04225SDavid du Colombier }
145334e04225SDavid du Colombier 
145434e04225SDavid du Colombier void
fsdie(Srv *)145534e04225SDavid du Colombier fsdie(Srv*)
145634e04225SDavid du Colombier {
145734e04225SDavid du Colombier 	threadexitsall(nil);
145834e04225SDavid du Colombier }
145934e04225SDavid du Colombier 
146034e04225SDavid du Colombier Srv fs =
146134e04225SDavid du Colombier {
146234e04225SDavid du Colombier .destroyfid =	fsdestroyfid,
146334e04225SDavid du Colombier .attach=		fssend,
146434e04225SDavid du Colombier .open=		fssend,
146534e04225SDavid du Colombier .create=		fssend,
146634e04225SDavid du Colombier .read=		fssend,
146734e04225SDavid du Colombier .write=		fssend,
146834e04225SDavid du Colombier .remove=		fssend,
146934e04225SDavid du Colombier .flush=		fssend,
147034e04225SDavid du Colombier .stat=		fssend,
147134e04225SDavid du Colombier .wstat=		fssend,
147234e04225SDavid du Colombier .walk=		fssend,
147334e04225SDavid du Colombier .end=		fsdie
147434e04225SDavid du Colombier };
147534e04225SDavid du Colombier 
147634e04225SDavid du Colombier void
usage(void)147734e04225SDavid du Colombier usage(void)
147834e04225SDavid du Colombier {
147934e04225SDavid du Colombier 	fprint(2, "usage: nfs [-DRv] [-p perm] [-s srvname] [-u passwd group] addr [addr]\n");
148034e04225SDavid du Colombier 	fprint(2, "\taddr - address of portmapper server\n");
148134e04225SDavid du Colombier 	fprint(2, "\taddr addr - addresses of mount server and nfs server\n");
148234e04225SDavid du Colombier 	exits("usage");
148334e04225SDavid du Colombier }
148434e04225SDavid du Colombier 
148534e04225SDavid du Colombier char*
netchangeport(char * addr,uint port,char * buf,uint nbuf)148634e04225SDavid du Colombier netchangeport(char *addr, uint port, char *buf, uint nbuf)
148734e04225SDavid du Colombier {
148834e04225SDavid du Colombier 	char *r;
148934e04225SDavid du Colombier 
149034e04225SDavid du Colombier 	strecpy(buf, buf+nbuf, addr);
149134e04225SDavid du Colombier 	r = strrchr(buf, '!');
149234e04225SDavid du Colombier 	if(r == nil)
149334e04225SDavid du Colombier 		return nil;
149434e04225SDavid du Colombier 	r++;
149534e04225SDavid du Colombier 	seprint(r, buf+nbuf, "%ud", port);
149634e04225SDavid du Colombier 	return buf;
149734e04225SDavid du Colombier }
149834e04225SDavid du Colombier 
149934e04225SDavid du Colombier char mbuf[256], nbuf[256];
150034e04225SDavid du Colombier char *mountaddr, *nfsaddr;
150134e04225SDavid du Colombier Channel *csync;
150234e04225SDavid du Colombier int chattyrpc;
150334e04225SDavid du Colombier void dialproc(void*);
150434e04225SDavid du Colombier 
150534e04225SDavid du Colombier void
threadmain(int argc,char ** argv)150634e04225SDavid du Colombier threadmain(int argc, char **argv)
150734e04225SDavid du Colombier {
150834e04225SDavid du Colombier 	char *srvname, *passwd, *group, *addr, *p;
150934e04225SDavid du Colombier 	SunClient *cli;
151034e04225SDavid du Colombier 	int proto;
151134e04225SDavid du Colombier 	uint mport, nport;
151234e04225SDavid du Colombier 	ulong perm;
151334e04225SDavid du Colombier 	Dir d;
151434e04225SDavid du Colombier 
151534e04225SDavid du Colombier 	perm = 0600;
151634e04225SDavid du Colombier 	passwd = nil;
151734e04225SDavid du Colombier 	group = nil;
151834e04225SDavid du Colombier 	srvname = nil;
151934e04225SDavid du Colombier 	sys = sysname();
152034e04225SDavid du Colombier 	if(sys == nil)
152134e04225SDavid du Colombier 		sys = "plan9";
152234e04225SDavid du Colombier 	ARGBEGIN{
152334e04225SDavid du Colombier 	default:
152434e04225SDavid du Colombier 		usage();
152534e04225SDavid du Colombier 	case 'D':
152634e04225SDavid du Colombier 		chatty9p++;
152734e04225SDavid du Colombier 		break;
152834e04225SDavid du Colombier 	case 'R':
152934e04225SDavid du Colombier 		chattyrpc++;
153034e04225SDavid du Colombier 		break;
153134e04225SDavid du Colombier 	case 'p':
153234e04225SDavid du Colombier 		perm = strtol(EARGF(usage()), &p, 8);
153334e04225SDavid du Colombier 		if(perm==0 || *p != 0)
153434e04225SDavid du Colombier 			usage();
153534e04225SDavid du Colombier 		break;
153634e04225SDavid du Colombier 	case 's':
153734e04225SDavid du Colombier 		srvname = EARGF(usage());
153834e04225SDavid du Colombier 		break;
153934e04225SDavid du Colombier 	case 'u':
154034e04225SDavid du Colombier 		passwd = EARGF(usage());
154134e04225SDavid du Colombier 		group = EARGF(usage());
154234e04225SDavid du Colombier 		break;
154334e04225SDavid du Colombier 	case 'v':
154434e04225SDavid du Colombier 		verbose++;
154534e04225SDavid du Colombier 		break;
154634e04225SDavid du Colombier 	}ARGEND
154734e04225SDavid du Colombier 
154834e04225SDavid du Colombier 	if(argc != 1 && argc != 2)
154934e04225SDavid du Colombier 		usage();
155034e04225SDavid du Colombier 
155134e04225SDavid du Colombier 	if(srvname == nil)
155234e04225SDavid du Colombier 		srvname = argv[0];
155334e04225SDavid du Colombier 
155434e04225SDavid du Colombier 	fmtinstall('B', sunRpcFmt);
155534e04225SDavid du Colombier 	fmtinstall('C', sunCallFmt);
155634e04225SDavid du Colombier 	fmtinstall('H', encodefmt);
155734e04225SDavid du Colombier 	sunFmtInstall(&portProg);
155834e04225SDavid du Colombier 	sunFmtInstall(&nfs3Prog);
155934e04225SDavid du Colombier 	sunFmtInstall(&nfsMount3Prog);
156034e04225SDavid du Colombier 
156134e04225SDavid du Colombier 	if(passwd && (map = readmap(passwd, group)) == nil)
156234e04225SDavid du Colombier 		fprint(2, "warning: reading %s and %s: %r\n", passwd, group);
156334e04225SDavid du Colombier 
156434e04225SDavid du Colombier 	if(map == nil)
156534e04225SDavid du Colombier 		map = &emptymap;
156634e04225SDavid du Colombier 
156734e04225SDavid du Colombier 	if(argc == 1){
156834e04225SDavid du Colombier 		addr = netmkaddr(argv[0], "udp", "portmap");
156934e04225SDavid du Colombier 		if((cli = sunDial(addr)) == nil)
157034e04225SDavid du Colombier 			sysfatal("dial %s: %r", addr);
157134e04225SDavid du Colombier 		cli->chatty = chattyrpc;
157234e04225SDavid du Colombier 		sunClientProg(cli, &portProg);
157334e04225SDavid du Colombier 		if(strstr(addr, "udp!"))
157434e04225SDavid du Colombier 			proto = PortProtoUdp;
157534e04225SDavid du Colombier 		else
157634e04225SDavid du Colombier 			proto = PortProtoTcp;
157734e04225SDavid du Colombier 		if(getport(cli, NfsMount3Program, NfsMount3Version, proto, &mport) < 0)
157834e04225SDavid du Colombier 			sysfatal("lookup mount program port: %r");
157934e04225SDavid du Colombier 		if(getport(cli, Nfs3Program, Nfs3Version, proto, &nport) < 0)
158034e04225SDavid du Colombier 			sysfatal("lookup nfs program port: %r");
158134e04225SDavid du Colombier 		sunClientClose(cli);
158234e04225SDavid du Colombier 		mountaddr = netchangeport(addr, mport, mbuf, sizeof mbuf);
158334e04225SDavid du Colombier 		nfsaddr = netchangeport(addr, nport, nbuf, sizeof nbuf);
158434e04225SDavid du Colombier 		strcat(mountaddr, "!r");
158534e04225SDavid du Colombier 		strcat(nfsaddr, "!r");
158634e04225SDavid du Colombier 		if(verbose)
158734e04225SDavid du Colombier 			fprint(2, "nfs %s %s\n", mountaddr, nfsaddr);
158834e04225SDavid du Colombier 	}else{
158934e04225SDavid du Colombier 		mountaddr = argv[0];
159034e04225SDavid du Colombier 		nfsaddr = argv[1];
159134e04225SDavid du Colombier 	}
159234e04225SDavid du Colombier 
159334e04225SDavid du Colombier 	/* have to dial in another proc because it creates threads */
159434e04225SDavid du Colombier 	csync = chancreate(sizeof(void*), 0);
159534e04225SDavid du Colombier 	proccreate(dialproc, nil, SunStackSize);
159634e04225SDavid du Colombier 	recvp(csync);
159734e04225SDavid du Colombier 
159834e04225SDavid du Colombier 	threadpostmountsrv(&fs, srvname, nil, 0);
159934e04225SDavid du Colombier 	if(perm != 0600){
160034e04225SDavid du Colombier 		p = smprint("/srv/%s", srvname);
160134e04225SDavid du Colombier 		if(p){
160234e04225SDavid du Colombier 			nulldir(&d);
160334e04225SDavid du Colombier 			d.mode = perm;
160434e04225SDavid du Colombier 			dirwstat(p, &d);
160534e04225SDavid du Colombier 		}
160634e04225SDavid du Colombier 	}
160734e04225SDavid du Colombier 	threadexits(nil);
160834e04225SDavid du Colombier }
160934e04225SDavid du Colombier 
161034e04225SDavid du Colombier void
dialproc(void *)161134e04225SDavid du Colombier dialproc(void*)
161234e04225SDavid du Colombier {
161334e04225SDavid du Colombier 	rfork(RFNAMEG);
161434e04225SDavid du Colombier 	rfork(RFNOTEG);
161534e04225SDavid du Colombier 	if((mntcli = sunDial(mountaddr)) == nil)
161634e04225SDavid du Colombier 		sysfatal("dial mount program at %s: %r", mountaddr);
161734e04225SDavid du Colombier 	mntcli->chatty = chattyrpc;
161834e04225SDavid du Colombier 	sunClientProg(mntcli, &nfsMount3Prog);
161934e04225SDavid du Colombier 	if(mountNull(0) < 0)
162034e04225SDavid du Colombier 		sysfatal("execute nop with mnt server at %s: %r", mountaddr);
162134e04225SDavid du Colombier 
162234e04225SDavid du Colombier 	if((nfscli = sunDial(nfsaddr)) == nil)
162334e04225SDavid du Colombier 		sysfatal("dial nfs program at %s: %r", nfsaddr);
162434e04225SDavid du Colombier 	nfscli->chatty = chattyrpc;
162534e04225SDavid du Colombier 	sunClientProg(nfscli, &nfs3Prog);
162634e04225SDavid du Colombier 	if(nfsNull(0) < 0)
162734e04225SDavid du Colombier 		sysfatal("execute nop with nfs server at %s: %r", nfsaddr);
162834e04225SDavid du Colombier 
162934e04225SDavid du Colombier 	fschan = chancreate(sizeof(Req*), 0);
163034e04225SDavid du Colombier 	threadcreate(fsthread, nil, SunStackSize);
163134e04225SDavid du Colombier 	sendp(csync, 0);
163234e04225SDavid du Colombier }
1633