xref: /plan9/sys/src/cmd/nfs.c (revision f314cdf7834bd43eca346fc56576f76e4a83155b)
1 /* Copyright © 2003 Russ Cox, MIT; see /sys/src/libsunrpc/COPYING */
2 #include <u.h>
3 #include <libc.h>
4 #include <bio.h>
5 #include <fcall.h>
6 #include <thread.h>
7 #include <9p.h>
8 #include <sunrpc.h>
9 #include <nfs3.h>
10 
11 SunClient *nfscli;
12 SunClient *mntcli;
13 char *defaultpath = "/";
14 Channel *fschan;
15 char *sys;
16 int verbose;
17 int readplus = 0;
18 
19 
20 typedef struct Auth Auth;
21 struct Auth
22 {
23 	int ref;
24 	uchar *data;
25 	int ndata;
26 };
27 
28 typedef struct FidAux FidAux;
29 struct FidAux
30 {
31 	Nfs3Handle handle;
32 
33 	u64int cookie;	/* for continuing directory reads */
34 	char *name;	/* botch: for remove and rename */
35 	Nfs3Handle parent;	/* botch: for remove and rename */
36 	char err[ERRMAX];	/* for walk1 */
37 	Auth *auth;
38 };
39 
40 /*
41  * various RPCs.  here is where we'd insert support for NFS v2
42  */
43 
44 void
portCall(SunCall * c,PortCallType type)45 portCall(SunCall *c, PortCallType type)
46 {
47 	c->rpc.prog = PortProgram;
48 	c->rpc.vers = PortVersion;
49 	c->rpc.proc = type>>1;
50 	c->rpc.iscall = !(type&1);
51 	c->type = type;
52 }
53 
54 int
getport(SunClient * client,uint prog,uint vers,uint prot,uint * port)55 getport(SunClient *client, uint prog, uint vers, uint prot, uint *port)
56 {
57 	PortTGetport tx;
58 	PortRGetport rx;
59 
60 	memset(&tx, 0, sizeof tx);
61 	portCall(&tx.call, PortCallTGetport);
62 	tx.map.prog = prog;
63 	tx.map.vers = vers;
64 	tx.map.prot = prot;
65 
66 	memset(&rx, 0, sizeof rx);
67 	portCall(&rx.call, PortCallRGetport);
68 
69 	if(sunClientRpc(client, 0, &tx.call, &rx.call, nil) < 0)
70 		return -1;
71 	*port = rx.port;
72 	return 0;
73 }
74 
75 void
mountCall(Auth * a,SunCall * c,NfsMount3CallType type)76 mountCall(Auth *a, SunCall *c, NfsMount3CallType type)
77 {
78 	c->rpc.iscall = !(type&1);
79 	c->rpc.proc = type>>1;
80 	c->rpc.prog = NfsMount3Program;
81 	c->rpc.vers = NfsMount3Version;
82 	if(c->rpc.iscall && a){
83 		c->rpc.cred.flavor = SunAuthSys;
84 		c->rpc.cred.data = a->data;
85 		c->rpc.cred.ndata = a->ndata;
86 	}
87 	c->type = type;
88 }
89 
90 int
mountNull(ulong tag)91 mountNull(ulong tag)
92 {
93 	NfsMount3TNull tx;
94 	NfsMount3RNull rx;
95 
96 	memset(&tx, 0, sizeof tx);
97 	mountCall(nil, &tx.call, NfsMount3CallTNull);
98 
99 	memset(&rx, 0, sizeof rx);
100 	mountCall(nil, &rx.call, NfsMount3CallTNull);
101 
102 	return sunClientRpc(mntcli, tag, &tx.call, &rx.call, nil);
103 }
104 
105 int
mountMnt(Auth * a,ulong tag,char * path,Nfs3Handle * h)106 mountMnt(Auth *a, ulong tag, char *path, Nfs3Handle *h)
107 {
108 	uchar *freeme;
109 	NfsMount3TMnt tx;
110 	NfsMount3RMnt rx;
111 
112 	memset(&tx, 0, sizeof tx);
113 	mountCall(a, &tx.call, NfsMount3CallTMnt);
114 	tx.path = path;
115 
116 	memset(&rx, 0, sizeof rx);
117 	mountCall(a, &rx.call, NfsMount3CallRMnt);
118 	if(sunClientRpc(mntcli, tag, &tx.call, &rx.call, &freeme) < 0)
119 		return -1;
120 	if(rx.status != Nfs3Ok){
121 		nfs3Errstr(rx.status);
122 		return -1;
123 	}
124 if(verbose)print("handle %.*H\n", rx.len, rx.handle);
125 	if(rx.len >= Nfs3MaxHandleSize){
126 		free(freeme);
127 		werrstr("server-returned handle too long");
128 		return -1;
129 	}
130 	memmove(h->h, rx.handle, rx.len);
131 	h->len = rx.len;
132 	free(freeme);
133 	return 0;
134 }
135 
136 void
nfs3Call(Auth * a,SunCall * c,Nfs3CallType type)137 nfs3Call(Auth *a, SunCall *c, Nfs3CallType type)
138 {
139 	c->rpc.iscall = !(type&1);
140 	c->rpc.proc = type>>1;
141 	c->rpc.prog = Nfs3Program;
142 	c->rpc.vers = Nfs3Version;
143 	if(c->rpc.iscall && a){
144 		c->rpc.cred.flavor = SunAuthSys;
145 		c->rpc.cred.data = a->data;
146 		c->rpc.cred.ndata = a->ndata;
147 	}
148 	c->type = type;
149 }
150 
151 int
nfsNull(ulong tag)152 nfsNull(ulong tag)
153 {
154 	Nfs3TNull tx;
155 	Nfs3RNull rx;
156 
157 	memset(&tx, 0, sizeof tx);
158 	nfs3Call(nil, &tx.call, Nfs3CallTNull);
159 
160 	memset(&rx, 0, sizeof rx);
161 	nfs3Call(nil, &rx.call, Nfs3CallTNull);
162 
163 	return sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil);
164 }
165 
166 int
nfsGetattr(Auth * a,ulong tag,Nfs3Handle * h,Nfs3Attr * attr)167 nfsGetattr(Auth *a, ulong tag, Nfs3Handle *h, Nfs3Attr *attr)
168 {
169 	Nfs3TGetattr tx;
170 	Nfs3RGetattr rx;
171 
172 	memset(&tx, 0, sizeof tx);
173 	nfs3Call(a, &tx.call, Nfs3CallTGetattr);
174 	tx.handle = *h;
175 
176 	memset(&rx, 0, sizeof rx);
177 	nfs3Call(a, &rx.call, Nfs3CallRGetattr);
178 
179 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
180 		return -1;
181 	if(rx.status != Nfs3Ok){
182 		nfs3Errstr(rx.status);
183 		return -1;
184 	}
185 
186 	*attr = rx.attr;
187 	return 0;
188 }
189 
190 int
nfsAccess(Auth * a,ulong tag,Nfs3Handle * h,ulong want,ulong * got,u1int * have,Nfs3Attr * attr)191 nfsAccess(Auth *a, ulong tag, Nfs3Handle *h, ulong want, ulong *got, u1int *have, Nfs3Attr *attr)
192 {
193 	Nfs3TAccess tx;
194 	Nfs3RAccess rx;
195 
196 	memset(&tx, 0, sizeof tx);
197 	nfs3Call(a, &tx.call, Nfs3CallTAccess);
198 	tx.handle = *h;
199 	tx.access = want;
200 
201 	memset(&rx, 0, sizeof rx);
202 	nfs3Call(a, &rx.call, Nfs3CallRAccess);
203 
204 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
205 		return -1;
206 	if(rx.status != Nfs3Ok){
207 		nfs3Errstr(rx.status);
208 		return -1;
209 	}
210 
211 	*got = rx.access;
212 
213 	*have = rx.haveAttr;
214 	if(rx.haveAttr)
215 		*attr = rx.attr;
216 	return 0;
217 }
218 
219 int
nfsMkdir(Auth * a,ulong tag,Nfs3Handle * h,char * name,Nfs3Handle * nh,ulong mode,uint gid,u1int * have,Nfs3Attr * attr)220 nfsMkdir(Auth *a, ulong tag, Nfs3Handle *h, char *name, Nfs3Handle *nh, ulong mode, uint gid,
221 	u1int *have, Nfs3Attr *attr)
222 {
223 	Nfs3TMkdir tx;
224 	Nfs3RMkdir rx;
225 
226 	memset(&tx, 0, sizeof tx);
227 	nfs3Call(a, &tx.call, Nfs3CallTMkdir);
228 	tx.handle = *h;
229 	tx.name = name;
230 	tx.attr.setMode = 1;
231 	tx.attr.mode = mode;
232 	tx.attr.setGid = 1;
233 	tx.attr.gid = gid;
234 
235 	memset(&rx, 0, sizeof rx);
236 	nfs3Call(a, &rx.call, Nfs3CallRMkdir);
237 
238 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
239 		return -1;
240 	if(rx.status != Nfs3Ok){
241 		nfs3Errstr(rx.status);
242 		return -1;
243 	}
244 
245 	if(!rx.haveHandle){
246 		werrstr("nfs mkdir did not return handle");
247 		return -1;
248 	}
249 	*nh = rx.handle;
250 
251 	*have = rx.haveAttr;
252 	if(rx.haveAttr)
253 		*attr = rx.attr;
254 	return 0;
255 }
256 
257 int
nfsCreate(Auth * a,ulong tag,Nfs3Handle * h,char * name,Nfs3Handle * nh,ulong mode,uint gid,u1int * have,Nfs3Attr * attr)258 nfsCreate(Auth *a, ulong tag, Nfs3Handle *h, char *name, Nfs3Handle *nh, ulong mode, uint gid,
259 	u1int *have, Nfs3Attr *attr)
260 {
261 	Nfs3TCreate tx;
262 	Nfs3RCreate rx;
263 
264 	memset(&tx, 0, sizeof tx);
265 	nfs3Call(a, &tx.call, Nfs3CallTCreate);
266 	tx.handle = *h;
267 	tx.name = name;
268 	tx.attr.setMode = 1;
269 	tx.attr.mode = mode;
270 	tx.attr.setGid = 1;
271 	tx.attr.gid = gid;
272 
273 	memset(&rx, 0, sizeof rx);
274 	nfs3Call(a, &rx.call, Nfs3CallRCreate);
275 
276 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
277 		return -1;
278 	if(rx.status != Nfs3Ok){
279 		nfs3Errstr(rx.status);
280 		return -1;
281 	}
282 
283 	if(!rx.haveHandle){
284 		werrstr("nfs create did not return handle");
285 		return -1;
286 	}
287 	*nh = rx.handle;
288 
289 	*have = rx.haveAttr;
290 	if(rx.haveAttr)
291 		*attr = rx.attr;
292 	return 0;
293 }
294 
295 int
nfsRead(Auth * a,ulong tag,Nfs3Handle * h,u32int count,u64int offset,uchar ** pp,u32int * pcount,uchar ** pfreeme)296 nfsRead(Auth *a, ulong tag, Nfs3Handle *h, u32int count, u64int offset,
297 	uchar **pp, u32int *pcount, uchar **pfreeme)
298 {
299 	uchar *freeme;
300 	Nfs3TRead tx;
301 	Nfs3RRead rx;
302 
303 	memset(&tx, 0, sizeof tx);
304 	nfs3Call(a, &tx.call, Nfs3CallTRead);
305 	tx.handle = *h;
306 	tx.count = count;
307 	tx.offset = offset;
308 
309 	memset(&rx, 0, sizeof rx);
310 	nfs3Call(a, &rx.call, Nfs3CallRRead);
311 
312 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, &freeme) < 0)
313 		return -1;
314 	if(rx.status != Nfs3Ok){
315 		nfs3Errstr(rx.status);
316 		return -1;
317 	}
318 	if(rx.count != rx.ndata){
319 		werrstr("nfs read returned count=%ud ndata=%ud", (uint)rx.count, (uint)rx.ndata);
320 		free(freeme);
321 		return -1;
322 	}
323 	*pfreeme = freeme;
324 	*pcount = rx.count;
325 	*pp = rx.data;
326 	return 0;
327 }
328 
329 int
nfsWrite(Auth * a,ulong tag,Nfs3Handle * h,uchar * data,u32int count,u64int offset,u32int * pcount)330 nfsWrite(Auth *a, ulong tag, Nfs3Handle *h, uchar *data, u32int count, u64int offset, u32int *pcount)
331 {
332 	Nfs3TWrite tx;
333 	Nfs3RWrite rx;
334 
335 	memset(&tx, 0, sizeof tx);
336 	nfs3Call(a, &tx.call, Nfs3CallTWrite);
337 	tx.handle = *h;
338 	tx.count = count;
339 	tx.offset = offset;
340 	tx.data = data;
341 	tx.ndata = count;
342 
343 	memset(&rx, 0, sizeof rx);
344 	nfs3Call(a, &rx.call, Nfs3CallRWrite);
345 
346 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
347 		return -1;
348 	if(rx.status != Nfs3Ok){
349 		nfs3Errstr(rx.status);
350 		return -1;
351 	}
352 
353 	*pcount = rx.count;
354 	return 0;
355 }
356 
357 int
nfsRmdir(Auth * a,ulong tag,Nfs3Handle * h,char * name)358 nfsRmdir(Auth *a, ulong tag, Nfs3Handle *h, char *name)
359 {
360 	Nfs3TRmdir tx;
361 	Nfs3RRmdir rx;
362 
363 	memset(&tx, 0, sizeof tx);
364 	nfs3Call(a, &tx.call, Nfs3CallTRmdir);
365 	tx.handle = *h;
366 	tx.name = name;
367 
368 	memset(&rx, 0, sizeof rx);
369 	nfs3Call(a, &rx.call, Nfs3CallRRmdir);
370 
371 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
372 		return -1;
373 	if(rx.status != Nfs3Ok){
374 		nfs3Errstr(rx.status);
375 		return -1;
376 	}
377 	return 0;
378 }
379 
380 int
nfsRemove(Auth * a,ulong tag,Nfs3Handle * h,char * name)381 nfsRemove(Auth *a, ulong tag, Nfs3Handle *h, char *name)
382 {
383 	Nfs3TRemove tx;
384 	Nfs3RRemove rx;
385 
386 	memset(&tx, 0, sizeof tx);
387 	nfs3Call(a, &tx.call, Nfs3CallTRemove);
388 	tx.handle = *h;
389 	tx.name = name;
390 
391 	memset(&rx, 0, sizeof rx);
392 	nfs3Call(a, &rx.call, Nfs3CallRRemove);
393 
394 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
395 		return -1;
396 	if(rx.status != Nfs3Ok){
397 		nfs3Errstr(rx.status);
398 		return -1;
399 	}
400 	return 0;
401 }
402 
403 int
nfsRename(Auth * a,ulong tag,Nfs3Handle * h,char * name,Nfs3Handle * th,char * tname)404 nfsRename(Auth *a, ulong tag, Nfs3Handle *h, char *name, Nfs3Handle *th, char *tname)
405 {
406 	Nfs3TRename tx;
407 	Nfs3RRename rx;
408 
409 	memset(&tx, 0, sizeof tx);
410 	nfs3Call(a, &tx.call, Nfs3CallTRename);
411 	tx.from.handle = *h;
412 	tx.from.name = name;
413 	tx.to.handle = *th;
414 	tx.to.name = tname;
415 
416 	memset(&rx, 0, sizeof rx);
417 	nfs3Call(a, &rx.call, Nfs3CallRRename);
418 
419 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
420 		return -1;
421 	if(rx.status != Nfs3Ok){
422 		nfs3Errstr(rx.status);
423 		return -1;
424 	}
425 	return 0;
426 }
427 
428 int
nfsSetattr(Auth * a,ulong tag,Nfs3Handle * h,Nfs3SetAttr * attr)429 nfsSetattr(Auth *a, ulong tag, Nfs3Handle *h, Nfs3SetAttr *attr)
430 {
431 	Nfs3TSetattr tx;
432 	Nfs3RSetattr rx;
433 
434 	memset(&tx, 0, sizeof tx);
435 	nfs3Call(a, &tx.call, Nfs3CallTSetattr);
436 	tx.handle = *h;
437 	tx.attr = *attr;
438 
439 	memset(&rx, 0, sizeof rx);
440 	nfs3Call(a, &rx.call, Nfs3CallRSetattr);
441 
442 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
443 		return -1;
444 	if(rx.status != Nfs3Ok){
445 		nfs3Errstr(rx.status);
446 		return -1;
447 	}
448 	return 0;
449 }
450 
451 int
nfsCommit(Auth * a,ulong tag,Nfs3Handle * h)452 nfsCommit(Auth *a, ulong tag, Nfs3Handle *h)
453 {
454 	Nfs3TCommit tx;
455 	Nfs3RCommit rx;
456 
457 	memset(&tx, 0, sizeof tx);
458 	nfs3Call(a, &tx.call, Nfs3CallTCommit);
459 	tx.handle = *h;
460 
461 	memset(&rx, 0, sizeof rx);
462 	nfs3Call(a, &rx.call, Nfs3CallRCommit);
463 
464 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
465 		return -1;
466 
467 	if(rx.status != Nfs3Ok){
468 		nfs3Errstr(rx.status);
469 		return -1;
470 	}
471 	return 0;
472 }
473 
474 int
nfsLookup(Auth * a,ulong tag,Nfs3Handle * h,char * name,Nfs3Handle * nh,u1int * have,Nfs3Attr * attr)475 nfsLookup(Auth *a, ulong tag, Nfs3Handle *h, char *name, Nfs3Handle *nh, u1int *have, Nfs3Attr *attr)
476 {
477 	Nfs3TLookup tx;
478 	Nfs3RLookup rx;
479 
480 	memset(&tx, 0, sizeof tx);
481 	nfs3Call(a, &tx.call, Nfs3CallTLookup);
482 	tx.handle = *h;
483 	tx.name = name;
484 
485 	memset(&rx, 0, sizeof rx);
486 	nfs3Call(a, &rx.call, Nfs3CallRLookup);
487 
488 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, nil) < 0)
489 		return -1;
490 
491 	if(rx.status != Nfs3Ok){
492 		nfs3Errstr(rx.status);
493 		return -1;
494 	}
495 	*nh = rx.handle;
496 	*have = rx.haveAttr;
497 	if(rx.haveAttr)
498 		*attr = rx.attr;
499 	return 0;
500 }
501 
502 int
nfsReadDirPlus(Auth * a,ulong tag,Nfs3Handle * h,u32int count,u64int cookie,uchar ** pp,u32int * pcount,int (** unpack)(uchar *,uchar *,uchar **,Nfs3Entry *),uchar ** pfreeme)503 nfsReadDirPlus(Auth *a, ulong tag, Nfs3Handle *h, u32int count, u64int cookie, uchar **pp,
504 	u32int *pcount, int (**unpack)(uchar*, uchar*, uchar**, Nfs3Entry*), uchar **pfreeme)
505 {
506 	Nfs3TReadDirPlus tx;
507 	Nfs3RReadDirPlus rx;
508 
509 	memset(&tx, 0, sizeof tx);
510 	nfs3Call(a, &tx.call, Nfs3CallTReadDirPlus);
511 	tx.handle = *h;
512 	tx.maxCount = count;
513 	tx.dirCount = 1000;
514 	tx.cookie = cookie;
515 
516 	memset(&rx, 0, sizeof rx);
517 	nfs3Call(a, &rx.call, Nfs3CallRReadDirPlus);
518 
519 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, pfreeme) < 0)
520 		return -1;
521 	if(rx.status != Nfs3Ok){
522 		free(*pfreeme);
523 		*pfreeme = 0;
524 		nfs3Errstr(rx.status);
525 		return -1;
526 	}
527 
528 	*unpack = nfs3EntryPlusUnpack;
529 	*pcount = rx.count;
530 	*pp = rx.data;
531 	return 0;
532 }
533 
534 int
nfsReadDir(Auth * a,ulong tag,Nfs3Handle * h,u32int count,u64int cookie,uchar ** pp,u32int * pcount,int (** unpack)(uchar *,uchar *,uchar **,Nfs3Entry *),uchar ** pfreeme)535 nfsReadDir(Auth *a, ulong tag, Nfs3Handle *h, u32int count, u64int cookie, uchar **pp,
536 	u32int *pcount, int (**unpack)(uchar*, uchar*, uchar**, Nfs3Entry*), uchar **pfreeme)
537 {
538 	/* BUG: try readdirplus */
539 	char e[ERRMAX];
540 	Nfs3TReadDir tx;
541 	Nfs3RReadDir rx;
542 
543 	if(readplus!=-1){
544 		if(nfsReadDirPlus(a, tag, h, count, cookie, pp, pcount, unpack, pfreeme) == 0){
545 			readplus = 1;
546 			return 0;
547 		}
548 		if(readplus == 0){
549 			rerrstr(e, sizeof e);
550 			if(strstr(e, "procedure unavailable") || strstr(e, "not supported"))
551 				readplus = -1;
552 		}
553 		if(readplus == 0)
554 			fprint(2, "readdirplus: %r\n");
555 	}
556 	if(readplus == 1)
557 		return -1;
558 
559 	memset(&tx, 0, sizeof tx);
560 	nfs3Call(a, &tx.call, Nfs3CallTReadDir);
561 	tx.handle = *h;
562 	tx.count = count;
563 	tx.cookie = cookie;
564 
565 	memset(&rx, 0, sizeof rx);
566 	nfs3Call(a, &rx.call, Nfs3CallRReadDir);
567 
568 	if(sunClientRpc(nfscli, tag, &tx.call, &rx.call, pfreeme) < 0)
569 		return -1;
570 	if(rx.status != Nfs3Ok){
571 		free(*pfreeme);
572 		*pfreeme = 0;
573 		nfs3Errstr(rx.status);
574 		return -1;
575 	}
576 
577 	/* readplus failed but read succeeded */
578 	readplus = -1;
579 
580 	*unpack = nfs3EntryUnpack;
581 	*pcount = rx.count;
582 	*pp = rx.data;
583 	return 0;
584 }
585 
586 /*
587  * name <-> int translation
588  */
589 typedef struct Map Map;
590 typedef struct User User;
591 typedef struct Group Group;
592 
593 Map *map;
594 Map emptymap;
595 
596 struct User
597 {
598 	char *name;
599 	uint uid;
600 	uint gid;
601 	uint g[16];
602 	uint ng;
603 	uchar *auth;
604 	int nauth;
605 };
606 
607 struct Group
608 {
609 	char *name;	/* same pos as in User struct */
610 	uint gid;	/* same pos as in User struct */
611 };
612 
613 struct Map
614 {
615 	int nuser;
616 	int ngroup;
617 	User *user;
618 	User **ubyname;
619 	User **ubyid;
620 	Group *group;
621 	Group **gbyname;
622 	Group **gbyid;
623 };
624 
625 User*
finduser(User ** u,int nu,char * s)626 finduser(User **u, int nu, char *s)
627 {
628 	int lo, hi, mid, n;
629 
630 	hi = nu;
631 	lo = 0;
632 	while(hi > lo){
633 		mid = (lo+hi)/2;
634 		n = strcmp(u[mid]->name, s);
635 		if(n == 0)
636 			return u[mid];
637 		if(n < 0)
638 			lo = mid+1;
639 		else
640 			hi = mid;
641 	}
642 	return nil;
643 }
644 
645 int
strtoid(User ** u,int nu,char * s,u32int * id)646 strtoid(User **u, int nu, char *s, u32int *id)
647 {
648 	u32int x;
649 	char *p;
650 	User *uu;
651 
652 	x = strtoul(s, &p, 10);
653 	if(*s != 0 && *p == 0){
654 		*id = x;
655 		return 0;
656 	}
657 
658 	uu = finduser(u, nu, s);
659 	if(uu == nil)
660 		return -1;
661 	*id = uu->uid;
662 	return 0;
663 }
664 
665 char*
idtostr(User ** u,int nu,u32int id)666 idtostr(User **u, int nu, u32int id)
667 {
668 	char buf[32];
669 	int lo, hi, mid;
670 
671 	hi = nu;
672 	lo = 0;
673 	while(hi > lo){
674 		mid = (lo+hi)/2;
675 		if(u[mid]->uid == id)
676 			return estrdup9p(u[mid]->name);
677 		if(u[mid]->uid < id)
678 			lo = mid+1;
679 		else
680 			hi = mid;
681 	}
682 	snprint(buf, sizeof buf, "%ud", id);
683 	return estrdup9p(buf);
684 }
685 char*
uidtostr(u32int uid)686 uidtostr(u32int uid)
687 {
688 	return idtostr(map->ubyid, map->nuser, uid);
689 }
690 
691 char*
gidtostr(u32int gid)692 gidtostr(u32int gid)
693 {
694 	return idtostr((User**)map->gbyid, map->ngroup, gid);
695 }
696 
697 int
strtouid(char * s,u32int * id)698 strtouid(char *s, u32int *id)
699 {
700 	return strtoid(map->ubyname, map->nuser, s, id);
701 }
702 
703 int
strtogid(char * s,u32int * id)704 strtogid(char *s, u32int *id)
705 {
706 	return strtoid((User**)map->gbyid, map->ngroup, s, id);
707 }
708 
709 
710 int
idcmp(const void * va,const void * vb)711 idcmp(const void *va, const void *vb)
712 {
713 	User **a, **b;
714 
715 	a = (User**)va;
716 	b = (User**)vb;
717 	return (*a)->uid - (*b)->uid;
718 }
719 
720 int
namecmp(const void * va,const void * vb)721 namecmp(const void *va, const void *vb)
722 {
723 	User **a, **b;
724 
725 	a = (User**)va;
726 	b = (User**)vb;
727 	return strcmp((*a)->name, (*b)->name);
728 }
729 
730 void
closemap(Map * m)731 closemap(Map *m)
732 {
733 	int i;
734 
735 	for(i=0; i<m->nuser; i++){
736 		free(m->user[i].name);
737 		free(m->user[i].auth);
738 	}
739 	for(i=0; i<m->ngroup; i++)
740 		free(m->group[i].name);
741 	free(m->user);
742 	free(m->group);
743 	free(m->ubyid);
744 	free(m->ubyname);
745 	free(m->gbyid);
746 	free(m->gbyname);
747 	free(m);
748 }
749 
750 Map*
readmap(char * passwd,char * group)751 readmap(char *passwd, char *group)
752 {
753 	char *s, *f[10], *p, *nextp, *name;
754 	uchar *q, *eq;
755 	int i, n, nf, line, uid, gid;
756 	Biobuf *b;
757 	Map *m;
758 	User *u;
759 	Group *g;
760 	SunAuthUnix au;
761 
762 	m = emalloc(sizeof(Map));
763 
764 	if((b = Bopen(passwd, OREAD)) == nil){
765 		free(m);
766 		return nil;
767 	}
768 	line = 0;
769 	for(; (s = Brdstr(b, '\n', 1)) != nil; free(s)){
770 		line++;
771 		if(s[0] == '#')
772 			continue;
773 		nf = getfields(s, f, nelem(f), 0, ":");
774 		if(nf < 4)
775 			continue;
776 		name = f[0];
777 		uid = strtol(f[2], &p, 10);
778 		if(f[2][0] == 0 || *p != 0){
779 			fprint(2, "%s:%d: non-numeric id in third field\n", passwd, line);
780 			continue;
781 		}
782 		gid = strtol(f[3], &p, 10);
783 		if(f[3][0] == 0 || *p != 0){
784 			fprint(2, "%s:%d: non-numeric id in fourth field\n", passwd, line);
785 			continue;
786 		}
787 		if(m->nuser%32 == 0)
788 			m->user = erealloc(m->user, (m->nuser+32)*sizeof(m->user[0]));
789 		u = &m->user[m->nuser++];
790 		u->name = estrdup9p(name);
791 		u->uid = uid;
792 		u->gid = gid;
793 		u->ng = 0;
794 		u->auth = 0;
795 		u->nauth = 0;
796 	}
797 	Bterm(b);
798 	m->ubyname = emalloc(m->nuser*sizeof(User*));
799 	m->ubyid = emalloc(m->nuser*sizeof(User*));
800 	for(i=0; i<m->nuser; i++){
801 		m->ubyname[i] = &m->user[i];
802 		m->ubyid[i] = &m->user[i];
803 	}
804 	qsort(m->ubyname, m->nuser, sizeof(m->ubyname[0]), namecmp);
805 	qsort(m->ubyid, m->nuser, sizeof(m->ubyid[0]), idcmp);
806 
807 	if((b = Bopen(group, OREAD)) == nil){
808 		closemap(m);
809 		return nil;
810 	}
811 	line = 0;
812 	for(; (s = Brdstr(b, '\n', 1)) != nil; free(s)){
813 		line++;
814 		if(s[0] == '#')
815 			continue;
816 		nf = getfields(s, f, nelem(f), 0, ":");
817 		if(nf < 4)
818 			continue;
819 		name = f[0];
820 		gid = strtol(f[2], &p, 10);
821 		if(f[2][0] == 0 || *p != 0){
822 			fprint(2, "%s:%d: non-numeric id in third field\n", group, line);
823 			continue;
824 		}
825 		if(m->ngroup%32 == 0)
826 			m->group = erealloc(m->group, (m->ngroup+32)*sizeof(m->group[0]));
827 		g = &m->group[m->ngroup++];
828 		g->name = estrdup9p(name);
829 		g->gid = gid;
830 
831 		for(p=f[3]; *p; p=nextp){
832 			if((nextp = strchr(p, ',')) != nil)
833 				*nextp++ = 0;
834 			else
835 				nextp = p+strlen(p);
836 			u = finduser(m->ubyname, m->nuser, p);
837 			if(u == nil){
838 				if(verbose)
839 					fprint(2, "%s:%d: unknown user %s\n", group, line, p);
840 				continue;
841 			}
842 			if(u->ng >= nelem(u->g)){
843 				fprint(2, "%s:%d: user %s is in too many groups; ignoring %s\n", group, line, p, name);
844 				continue;
845 			}
846 			u->g[u->ng++] = gid;
847 		}
848 	}
849 	Bterm(b);
850 	m->gbyname = emalloc(m->ngroup*sizeof(Group*));
851 	m->gbyid = emalloc(m->ngroup*sizeof(Group*));
852 	for(i=0; i<m->ngroup; i++){
853 		m->gbyname[i] = &m->group[i];
854 		m->gbyid[i] = &m->group[i];
855 	}
856 	qsort(m->gbyname, m->ngroup, sizeof(m->gbyname[0]), namecmp);
857 	qsort(m->gbyid, m->ngroup, sizeof(m->gbyid[0]), idcmp);
858 
859 	for(i=0; i<m->nuser; i++){
860 		au.stamp = 0;
861 		au.sysname = sys;
862 		au.uid = m->user[i].uid;
863 		au.gid = m->user[i].gid;
864 		memmove(au.g, m->user[i].g, sizeof au.g);
865 		au.ng = m->user[i].ng;
866 		n = sunAuthUnixSize(&au);
867 		q = emalloc(n);
868 		eq = q+n;
869 		m->user[i].auth = q;
870 		m->user[i].nauth = n;
871 		if(sunAuthUnixPack(q, eq, &q, &au) < 0 || q != eq){
872 			fprint(2, "sunAuthUnixPack failed for %s\n", m->user[i].name);
873 			free(m->user[i].auth);
874 			m->user[i].auth = 0;
875 			m->user[i].nauth = 0;
876 		}
877 	}
878 
879 	return m;
880 }
881 
882 Auth*
mkauth(char * user)883 mkauth(char *user)
884 {
885 	Auth *a;
886 	uchar *p;
887 	int n;
888 	SunAuthUnix au;
889 	User *u;
890 
891 	u = finduser(map->ubyname, map->nuser, user);
892 	if(u == nil || u->nauth == 0){
893 		/* nobody */
894 		au.stamp = 0;
895 		au.uid = -1;
896 		au.gid = -1;
897 		au.ng = 0;
898 		au.sysname = sys;
899 		n = sunAuthUnixSize(&au);
900 		a = emalloc(sizeof(Auth)+n);
901 		a->data = (uchar*)&a[1];
902 		a->ndata = n;
903 		if(sunAuthUnixPack(a->data, a->data+a->ndata, &p, &au) < 0
904 		|| p != a->data+a->ndata){
905 			free(a);
906 			return nil;
907 		}
908 		a->ref = 1;
909 if(verbose)print("creds for %s: %.*H\n", user, a->ndata, a->data);
910 		return a;
911 	}
912 
913 	a = emalloc(sizeof(Auth)+u->nauth);
914 	a->data = (uchar*)&a[1];
915 	a->ndata = u->nauth;
916 	memmove(a->data, u->auth, a->ndata);
917 	a->ref = 1;
918 if(verbose)print("creds for %s: %.*H\n", user, a->ndata, a->data);
919 	return a;
920 }
921 
922 void
freeauth(Auth * a)923 freeauth(Auth *a)
924 {
925 	if(--a->ref > 0)
926 		return;
927 	free(a);
928 }
929 
930 /*
931  * 9P server
932  */
933 void
responderrstr(Req * r)934 responderrstr(Req *r)
935 {
936 	char e[ERRMAX];
937 
938 	rerrstr(e, sizeof e);
939 	respond(r, e);
940 }
941 
942 void
fsdestroyfid(Fid * fid)943 fsdestroyfid(Fid *fid)
944 {
945 	FidAux *aux;
946 
947 	aux = fid->aux;
948 	if(aux == nil)
949 		return;
950 	freeauth(aux->auth);
951 	free(aux->name);
952 	free(aux);
953 }
954 
955 void
attrToQid(Nfs3Attr * attr,Qid * qid)956 attrToQid(Nfs3Attr *attr, Qid *qid)
957 {
958 	qid->path = attr->fileid;
959 	qid->vers = attr->mtime.sec;
960 	qid->type = 0;
961 	if(attr->type == Nfs3FileDir)
962 		qid->type |= QTDIR;
963 }
964 
965 void
attrToDir(Nfs3Attr * attr,Dir * d)966 attrToDir(Nfs3Attr *attr, Dir *d)
967 {
968 	d->mode = attr->mode & 0777;
969 	if(attr->type == Nfs3FileDir)
970 		d->mode |= DMDIR;
971 	d->uid = uidtostr(attr->uid);
972 	d->gid = gidtostr(attr->gid);
973 	d->length = attr->size;
974 	attrToQid(attr, &d->qid);
975 	d->mtime = attr->mtime.sec;
976 	d->atime = attr->atime.sec;
977 	d->muid = nil;
978 }
979 
980 void
fsattach(Req * r)981 fsattach(Req *r)
982 {
983 	char *path;
984 	Auth *auth;
985 	FidAux *aux;
986 	Nfs3Attr attr;
987 	Nfs3Handle h;
988 
989 	path = r->ifcall.aname;
990 	if(path==nil || path[0]==0)
991 		path = defaultpath;
992 
993 	auth = mkauth(r->ifcall.uname);
994 
995 	if(mountMnt(auth, r->tag, path, &h) < 0
996 	|| nfsGetattr(auth, r->tag, &h, &attr) < 0){
997 		freeauth(auth);
998 		responderrstr(r);
999 		return;
1000 	}
1001 
1002 	aux = emalloc(sizeof(FidAux));
1003 	aux->auth = auth;
1004 	aux->handle = h;
1005 	aux->cookie = 0;
1006 	aux->name = nil;
1007 	memset(&aux->parent, 0, sizeof aux->parent);
1008 	r->fid->aux = aux;
1009 	attrToQid(&attr, &r->fid->qid);
1010 	r->ofcall.qid = r->fid->qid;
1011 	respond(r, nil);
1012 }
1013 
1014 void
fsopen(Req * r)1015 fsopen(Req *r)
1016 {
1017 	FidAux *aux;
1018 	Nfs3Attr attr;
1019 	Nfs3SetAttr sa;
1020 	u1int have;
1021 	ulong a, b;
1022 
1023 	aux = r->fid->aux;
1024 	a = 0;
1025 	switch(r->ifcall.mode&OMASK){
1026 	case OREAD:
1027 		a = 0x0001;
1028 		break;
1029 	case OWRITE:
1030 		a = 0x0004;
1031 		break;
1032 	case ORDWR:
1033 		a = 0x0001|0x0004;
1034 		break;
1035 	case OEXEC:
1036 		a = 0x20;
1037 		break;
1038 	}
1039 	if(r->ifcall.mode&OTRUNC)
1040 		a |= 0x0004;
1041 
1042 	if(nfsAccess(aux->auth, r->tag, &aux->handle, a, &b, &have, &attr) < 0
1043 	|| (!have && nfsGetattr(aux->auth, r->tag, &aux->handle, &attr) < 0)){
1044     Error:
1045 		responderrstr(r);
1046 		return;
1047 	}
1048 	if(a != b){
1049 		respond(r, "permission denied");
1050 		return;
1051 	}
1052 	if(r->ifcall.mode&OTRUNC){
1053 		memset(&sa, 0, sizeof sa);
1054 		sa.setSize = 1;
1055 		if(nfsSetattr(aux->auth, r->tag, &aux->handle, &sa) < 0)
1056 			goto Error;
1057 	}
1058 	attrToQid(&attr, &r->fid->qid);
1059 	r->ofcall.qid = r->fid->qid;
1060 	respond(r, nil);
1061 }
1062 
1063 void
fscreate(Req * r)1064 fscreate(Req *r)
1065 {
1066 	FidAux *aux;
1067 	u1int have;
1068 	Nfs3Attr attr;
1069 	Nfs3Handle h;
1070 	ulong mode;
1071 	uint gid;
1072 	int (*mk)(Auth*, ulong, Nfs3Handle*, char*, Nfs3Handle*, ulong, uint, u1int*, Nfs3Attr*);
1073 
1074 	aux = r->fid->aux;
1075 
1076 	/*
1077 	 * Plan 9 has no umask, so let's use the
1078 	 * parent directory bits like Plan 9 does.
1079 	 * What the heck, let's inherit the group too.
1080 	 * (Unix will let us set the group to anything
1081 	 * since we're the owner!)
1082 	 */
1083 	if(nfsGetattr(aux->auth, r->tag, &aux->handle, &attr) < 0){
1084 		responderrstr(r);
1085 		return;
1086 	}
1087 	mode = r->ifcall.perm&0777;
1088 	if(r->ifcall.perm&DMDIR)
1089 		mode &= (attr.mode&0666) | ~0666;
1090 	else
1091 		mode &= (attr.mode&0777) | ~0777;
1092 	gid = attr.gid;
1093 
1094 	if(r->ifcall.perm&DMDIR)
1095 		mk = nfsMkdir;
1096 	else
1097 		mk = nfsCreate;
1098 
1099 	if((*mk)(aux->auth, r->tag, &aux->handle, r->ifcall.name, &h, mode, gid, &have, &attr) < 0
1100 	|| (!have && nfsGetattr(aux->auth, r->tag, &h, &attr) < 0)){
1101 		responderrstr(r);
1102 		return;
1103 	}
1104 	attrToQid(&attr, &r->fid->qid);
1105 	aux->parent = aux->handle;
1106 	aux->handle = h;
1107 	free(aux->name);
1108 	aux->name = estrdup9p(r->ifcall.name);
1109 	r->ofcall.qid = r->fid->qid;
1110 	respond(r, nil);
1111 }
1112 
1113 void
fsreaddir(Req * r)1114 fsreaddir(Req *r)
1115 {
1116 	FidAux *aux;
1117 	uchar *p, *freeme, *ep, *p9, *ep9;
1118 	char *s;
1119 	uint count;
1120 	int n, (*unpack)(uchar*, uchar*, uchar**, Nfs3Entry*);
1121 	Nfs3Entry e;
1122 	u64int cookie;
1123 	Dir d;
1124 
1125 	aux = r->fid->aux;
1126 	/*
1127 	 * r->ifcall.count seems a reasonable estimate to
1128 	 * how much NFS entry data we want.  is it?
1129 	 */
1130 	if(r->ifcall.offset)
1131 		cookie = aux->cookie;
1132 	else
1133 		cookie = 0;
1134 	if(nfsReadDir(aux->auth, r->tag, &aux->handle, r->ifcall.count, cookie,
1135 		&p, &count, &unpack, &freeme) < 0){
1136 		responderrstr(r);
1137 		return;
1138 	}
1139 	ep = p+count;
1140 
1141 	p9 = (uchar*)r->ofcall.data;
1142 	ep9 = p9+r->ifcall.count;
1143 
1144 	/*
1145 	 * BUG: Issue all of the stat requests in parallel.
1146 	 */
1147 	while(p < ep && p9 < ep9){
1148 		if((*unpack)(p, ep, &p, &e) < 0)
1149 			break;
1150 		aux->cookie = e.cookie;
1151 		if(strcmp(e.name, ".") == 0 || strcmp(e.name, "..") == 0)
1152 			continue;
1153 		for(s=e.name; (uchar)*s >= ' '; s++)
1154 			;
1155 		if(*s != 0)	/* bad character in name */
1156 			continue;
1157 		if(!e.haveAttr && !e.haveHandle)
1158 			if(nfsLookup(aux->auth, r->tag, &aux->handle, e.name, &e.handle, &e.haveAttr, &e.attr) < 0)
1159 				continue;
1160 		if(!e.haveAttr)
1161 			if(nfsGetattr(aux->auth, r->tag, &e.handle, &e.attr) < 0)
1162 				continue;
1163 		memset(&d, 0, sizeof d);
1164 		attrToDir(&e.attr, &d);
1165 		d.name = e.name;
1166 		if((n = convD2M(&d, p9, ep9-p9)) <= BIT16SZ)
1167 			break;
1168 		p9 += n;
1169 	}
1170 	free(freeme);
1171 	r->ofcall.count = p9 - (uchar*)r->ofcall.data;
1172 	respond(r, nil);
1173 }
1174 
1175 void
fsread(Req * r)1176 fsread(Req *r)
1177 {
1178 	uchar *p, *freeme;
1179 	uint count;
1180 	FidAux *aux;
1181 
1182 	if(r->fid->qid.type&QTDIR){
1183 		fsreaddir(r);
1184 		return;
1185 	}
1186 
1187 	aux = r->fid->aux;
1188 	if(nfsRead(aux->auth, r->tag, &aux->handle, r->ifcall.count, r->ifcall.offset, &p, &count, &freeme) < 0){
1189 		responderrstr(r);
1190 		return;
1191 	}
1192 	r->ofcall.data = (char*)p;
1193 	r->ofcall.count = count;
1194 	respond(r, nil);
1195 	free(freeme);
1196 }
1197 
1198 void
fswrite(Req * r)1199 fswrite(Req *r)
1200 {
1201 	uint count;
1202 	FidAux *aux;
1203 
1204 	aux = r->fid->aux;
1205 	if(nfsWrite(aux->auth, r->tag, &aux->handle, (uchar*)r->ifcall.data, r->ifcall.count, r->ifcall.offset, &count) < 0){
1206 		responderrstr(r);
1207 		return;
1208 	}
1209 	r->ofcall.count = count;
1210 	respond(r, nil);
1211 }
1212 
1213 void
fsremove(Req * r)1214 fsremove(Req *r)
1215 {
1216 	int n;
1217 	FidAux *aux;
1218 
1219 	aux = r->fid->aux;
1220 	if(aux->name == nil){
1221 		respond(r, "nfs3client botch -- don't know parent handle in remove");
1222 		return;
1223 	}
1224 	if(r->fid->qid.type&QTDIR)
1225 		n = nfsRmdir(aux->auth, r->tag, &aux->parent, aux->name);
1226 	else
1227 		n = nfsRemove(aux->auth, r->tag, &aux->parent, aux->name);
1228 	if(n < 0){
1229 		responderrstr(r);
1230 		return;
1231 	}
1232 	respond(r, nil);
1233 }
1234 
1235 void
fsstat(Req * r)1236 fsstat(Req *r)
1237 {
1238 	FidAux *aux;
1239 	Nfs3Attr attr;
1240 
1241 	aux = r->fid->aux;
1242 	if(nfsGetattr(aux->auth, r->tag, &aux->handle, &attr) < 0){
1243 		responderrstr(r);
1244 		return;
1245 	}
1246 	memset(&r->d, 0, sizeof r->d);
1247 	attrToDir(&attr, &r->d);
1248 	r->d.name = estrdup9p(aux->name ? aux->name : "???");
1249 	respond(r, nil);
1250 }
1251 
1252 void
fswstat(Req * r)1253 fswstat(Req *r)
1254 {
1255 	int op, sync;
1256 	FidAux *aux;
1257 	Nfs3SetAttr attr;
1258 
1259 	memset(&attr, 0, sizeof attr);
1260 	aux = r->fid->aux;
1261 
1262 	/* Fill out stat first to catch errors */
1263 	op = 0;
1264 	sync = 1;
1265 	if(~r->d.mode){
1266 		if(r->d.mode&(DMAPPEND|DMEXCL)){
1267 			respond(r, "wstat -- DMAPPEND and DMEXCL bits not supported");
1268 			return;
1269 		}
1270 		op = 1;
1271 		sync = 0;
1272 		attr.setMode = 1;
1273 		attr.mode = r->d.mode & 0777;
1274 	}
1275 	if(r->d.uid && r->d.uid[0]){
1276 		attr.setUid = 1;
1277 		if(strtouid(r->d.uid, &attr.uid) < 0){
1278 			respond(r, "wstat -- unknown uid");
1279 			return;
1280 		}
1281 		op = 1;
1282 		sync = 0;
1283 	}
1284 	if(r->d.gid && r->d.gid[0]){
1285 		attr.setGid = 1;
1286 		if(strtogid(r->d.gid, &attr.gid) < 0){
1287 			respond(r, "wstat -- unknown gid");
1288 			return;
1289 		}
1290 		op = 1;
1291 		sync = 0;
1292 	}
1293 	if(~r->d.length){
1294 		attr.setSize = 1;
1295 		attr.size = r->d.length;
1296 		op = 1;
1297 		sync = 0;
1298 	}
1299 	if(~r->d.mtime){
1300 		attr.setMtime = Nfs3SetTimeClient;
1301 		attr.mtime.sec = r->d.mtime;
1302 		op = 1;
1303 		sync = 0;
1304 	}
1305 	if(~r->d.atime){
1306 		attr.setAtime = Nfs3SetTimeClient;
1307 		attr.atime.sec = r->d.atime;
1308 		op = 1;
1309 		sync = 0;
1310 	}
1311 
1312 	/* Try rename first because it's more likely to fail (?) */
1313 	if(r->d.name && r->d.name[0]){
1314 		if(aux->name == nil){
1315 			respond(r, "nfsclient botch -- don't know parent handle in rename");
1316 			return;
1317 		}
1318 		if(nfsRename(aux->auth, r->tag, &aux->parent, aux->name, &aux->parent, r->d.name) < 0){
1319 			responderrstr(r);
1320 			return;
1321 		}
1322 		free(aux->name);
1323 		aux->name = estrdup9p(r->d.name);
1324 		sync = 0;
1325 	}
1326 
1327 	/*
1328 	 * Now we have a problem.  The rename succeeded
1329 	 * but the setattr could fail.  Sic transit atomicity.
1330 	 */
1331 	if(op){
1332 		if(nfsSetattr(aux->auth, r->tag, &aux->handle, &attr) < 0){
1333 			responderrstr(r);
1334 			return;
1335 		}
1336 	}
1337 
1338 	if(sync){
1339 		/* NFS commit */
1340 		if(nfsCommit(aux->auth, r->tag, &aux->handle) < 0){
1341 			responderrstr(r);
1342 			return;
1343 		}
1344 	}
1345 
1346 	respond(r, nil);
1347 }
1348 
1349 char*
fswalk1(Fid * fid,char * name,void * v)1350 fswalk1(Fid *fid, char *name, void *v)
1351 {
1352 	u1int have;
1353 	ulong tag;
1354 	FidAux *aux;
1355 	Nfs3Attr attr;
1356 	Nfs3Handle h;
1357 
1358 	tag = *(ulong*)v;
1359 	aux = fid->aux;
1360 
1361 	if(nfsLookup(aux->auth, tag, &aux->handle, name, &h, &have, &attr) < 0
1362 	|| (!have && nfsGetattr(aux->auth, tag, &h, &attr) < 0)){
1363 		rerrstr(aux->err, sizeof aux->err);
1364 		return aux->err;
1365 	}
1366 
1367 	aux->parent = aux->handle;
1368 	aux->handle = h;
1369 	free(aux->name);
1370 	if(strcmp(name, "..") == 0)
1371 		aux->name = nil;
1372 	else
1373 		aux->name = estrdup9p(name);
1374 	attrToQid(&attr, &fid->qid);
1375 	return nil;
1376 }
1377 
1378 char*
fsclone(Fid * fid,Fid * newfid,void *)1379 fsclone(Fid *fid, Fid *newfid, void*)
1380 {
1381 	FidAux *a, *na;
1382 
1383 	a = fid->aux;
1384 	na = emalloc9p(sizeof(FidAux));
1385 	*na = *a;
1386 	if(na->name)
1387 		na->name = estrdup9p(na->name);
1388 	newfid->aux = na;
1389 	if(na->auth)
1390 		na->auth->ref++;
1391 	return nil;
1392 }
1393 
1394 void
fswalk(Req * r)1395 fswalk(Req *r)
1396 {
1397 	walkandclone(r, fswalk1, fsclone, &r->tag);
1398 }
1399 
1400 void
fsflush(Req * r)1401 fsflush(Req *r)
1402 {
1403 	Req *or;
1404 
1405 	/*
1406 	 * Send on the flush channel(s).
1407 	 * The library will make sure the response
1408 	 * is delayed as necessary.
1409 	 */
1410 	or = r->oldreq;
1411 	if(nfscli)
1412 		sendul(nfscli->flushchan, (ulong)or->tag);
1413 	if(mntcli)
1414 		sendul(mntcli->flushchan, (ulong)or->tag);
1415 	respond(r, nil);
1416 }
1417 
1418 void
fsdispatch(void * v)1419 fsdispatch(void *v)
1420 {
1421 	Req *r;
1422 
1423 	r = v;
1424 	switch(r->ifcall.type){
1425 	default:	respond(r, "unknown type");	break;
1426 	case Tattach:	fsattach(r);	break;
1427 	case Topen:	fsopen(r);	break;
1428 	case Tcreate:	fscreate(r);	break;
1429 	case Tread:	fsread(r);	break;
1430 	case Twrite:	fswrite(r);	break;
1431 	case Tremove:	fsremove(r);	break;
1432 	case Tflush:	fsflush(r);	break;
1433 	case Tstat:	fsstat(r);	break;
1434 	case Twstat:	fswstat(r);	break;
1435 	case Twalk:	fswalk(r);	break;
1436 	}
1437 }
1438 
1439 void
fsthread(void *)1440 fsthread(void*)
1441 {
1442 	Req *r;
1443 
1444 	while((r = recvp(fschan)) != nil)
1445 		threadcreate(fsdispatch, r, SunStackSize);
1446 }
1447 
1448 void
fssend(Req * r)1449 fssend(Req *r)
1450 {
1451 	sendp(fschan, r);
1452 }
1453 
1454 void
fsdie(Srv *)1455 fsdie(Srv*)
1456 {
1457 	threadexitsall(nil);
1458 }
1459 
1460 Srv fs =
1461 {
1462 .destroyfid =	fsdestroyfid,
1463 .attach=		fssend,
1464 .open=		fssend,
1465 .create=		fssend,
1466 .read=		fssend,
1467 .write=		fssend,
1468 .remove=		fssend,
1469 .flush=		fssend,
1470 .stat=		fssend,
1471 .wstat=		fssend,
1472 .walk=		fssend,
1473 .end=		fsdie
1474 };
1475 
1476 void
usage(void)1477 usage(void)
1478 {
1479 	fprint(2, "usage: nfs [-DRv] [-p perm] [-s srvname] [-u passwd group] addr [addr]\n");
1480 	fprint(2, "\taddr - address of portmapper server\n");
1481 	fprint(2, "\taddr addr - addresses of mount server and nfs server\n");
1482 	exits("usage");
1483 }
1484 
1485 char*
netchangeport(char * addr,uint port,char * buf,uint nbuf)1486 netchangeport(char *addr, uint port, char *buf, uint nbuf)
1487 {
1488 	char *r;
1489 
1490 	strecpy(buf, buf+nbuf, addr);
1491 	r = strrchr(buf, '!');
1492 	if(r == nil)
1493 		return nil;
1494 	r++;
1495 	seprint(r, buf+nbuf, "%ud", port);
1496 	return buf;
1497 }
1498 
1499 char mbuf[256], nbuf[256];
1500 char *mountaddr, *nfsaddr;
1501 Channel *csync;
1502 int chattyrpc;
1503 void dialproc(void*);
1504 
1505 void
threadmain(int argc,char ** argv)1506 threadmain(int argc, char **argv)
1507 {
1508 	char *srvname, *passwd, *group, *addr, *p;
1509 	SunClient *cli;
1510 	int proto;
1511 	uint mport, nport;
1512 	ulong perm;
1513 	Dir d;
1514 
1515 	perm = 0600;
1516 	passwd = nil;
1517 	group = nil;
1518 	srvname = nil;
1519 	sys = sysname();
1520 	if(sys == nil)
1521 		sys = "plan9";
1522 	ARGBEGIN{
1523 	default:
1524 		usage();
1525 	case 'D':
1526 		chatty9p++;
1527 		break;
1528 	case 'R':
1529 		chattyrpc++;
1530 		break;
1531 	case 'p':
1532 		perm = strtol(EARGF(usage()), &p, 8);
1533 		if(perm==0 || *p != 0)
1534 			usage();
1535 		break;
1536 	case 's':
1537 		srvname = EARGF(usage());
1538 		break;
1539 	case 'u':
1540 		passwd = EARGF(usage());
1541 		group = EARGF(usage());
1542 		break;
1543 	case 'v':
1544 		verbose++;
1545 		break;
1546 	}ARGEND
1547 
1548 	if(argc != 1 && argc != 2)
1549 		usage();
1550 
1551 	if(srvname == nil)
1552 		srvname = argv[0];
1553 
1554 	fmtinstall('B', sunRpcFmt);
1555 	fmtinstall('C', sunCallFmt);
1556 	fmtinstall('H', encodefmt);
1557 	sunFmtInstall(&portProg);
1558 	sunFmtInstall(&nfs3Prog);
1559 	sunFmtInstall(&nfsMount3Prog);
1560 
1561 	if(passwd && (map = readmap(passwd, group)) == nil)
1562 		fprint(2, "warning: reading %s and %s: %r\n", passwd, group);
1563 
1564 	if(map == nil)
1565 		map = &emptymap;
1566 
1567 	if(argc == 1){
1568 		addr = netmkaddr(argv[0], "udp", "portmap");
1569 		if((cli = sunDial(addr)) == nil)
1570 			sysfatal("dial %s: %r", addr);
1571 		cli->chatty = chattyrpc;
1572 		sunClientProg(cli, &portProg);
1573 		if(strstr(addr, "udp!"))
1574 			proto = PortProtoUdp;
1575 		else
1576 			proto = PortProtoTcp;
1577 		if(getport(cli, NfsMount3Program, NfsMount3Version, proto, &mport) < 0)
1578 			sysfatal("lookup mount program port: %r");
1579 		if(getport(cli, Nfs3Program, Nfs3Version, proto, &nport) < 0)
1580 			sysfatal("lookup nfs program port: %r");
1581 		sunClientClose(cli);
1582 		mountaddr = netchangeport(addr, mport, mbuf, sizeof mbuf);
1583 		nfsaddr = netchangeport(addr, nport, nbuf, sizeof nbuf);
1584 		strcat(mountaddr, "!r");
1585 		strcat(nfsaddr, "!r");
1586 		if(verbose)
1587 			fprint(2, "nfs %s %s\n", mountaddr, nfsaddr);
1588 	}else{
1589 		mountaddr = argv[0];
1590 		nfsaddr = argv[1];
1591 	}
1592 
1593 	/* have to dial in another proc because it creates threads */
1594 	csync = chancreate(sizeof(void*), 0);
1595 	proccreate(dialproc, nil, SunStackSize);
1596 	recvp(csync);
1597 
1598 	threadpostmountsrv(&fs, srvname, nil, 0);
1599 	if(perm != 0600){
1600 		p = smprint("/srv/%s", srvname);
1601 		if(p){
1602 			nulldir(&d);
1603 			d.mode = perm;
1604 			dirwstat(p, &d);
1605 		}
1606 	}
1607 	threadexits(nil);
1608 }
1609 
1610 void
dialproc(void *)1611 dialproc(void*)
1612 {
1613 	rfork(RFNAMEG);
1614 	rfork(RFNOTEG);
1615 	if((mntcli = sunDial(mountaddr)) == nil)
1616 		sysfatal("dial mount program at %s: %r", mountaddr);
1617 	mntcli->chatty = chattyrpc;
1618 	sunClientProg(mntcli, &nfsMount3Prog);
1619 	if(mountNull(0) < 0)
1620 		sysfatal("execute nop with mnt server at %s: %r", mountaddr);
1621 
1622 	if((nfscli = sunDial(nfsaddr)) == nil)
1623 		sysfatal("dial nfs program at %s: %r", nfsaddr);
1624 	nfscli->chatty = chattyrpc;
1625 	sunClientProg(nfscli, &nfs3Prog);
1626 	if(nfsNull(0) < 0)
1627 		sysfatal("execute nop with nfs server at %s: %r", nfsaddr);
1628 
1629 	fschan = chancreate(sizeof(Req*), 0);
1630 	threadcreate(fsthread, nil, SunStackSize);
1631 	sendp(csync, 0);
1632 }
1633