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