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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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* 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 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* 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* 686 uidtostr(u32int uid) 687 { 688 return idtostr(map->ubyid, map->nuser, uid); 689 } 690 691 char* 692 gidtostr(u32int gid) 693 { 694 return idtostr((User**)map->gbyid, map->ngroup, gid); 695 } 696 697 int 698 strtouid(char *s, u32int *id) 699 { 700 return strtoid(map->ubyname, map->nuser, s, id); 701 } 702 703 int 704 strtogid(char *s, u32int *id) 705 { 706 return strtoid((User**)map->gbyid, map->ngroup, s, id); 707 } 708 709 710 int 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 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 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* 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* 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 923 freeauth(Auth *a) 924 { 925 if(--a->ref > 0) 926 return; 927 free(a); 928 } 929 930 /* 931 * 9P server 932 */ 933 void 934 responderrstr(Req *r) 935 { 936 char e[ERRMAX]; 937 938 rerrstr(e, sizeof e); 939 respond(r, e); 940 } 941 942 void 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 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 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 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 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 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 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 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 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 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 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 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* 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* 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 1395 fswalk(Req *r) 1396 { 1397 walkandclone(r, fswalk1, fsclone, &r->tag); 1398 } 1399 1400 void 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 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 1440 fsthread(void*) 1441 { 1442 Req *r; 1443 1444 while((r = recvp(fschan)) != nil) 1445 threadcreate(fsdispatch, r, SunStackSize); 1446 } 1447 1448 void 1449 fssend(Req *r) 1450 { 1451 sendp(fschan, r); 1452 } 1453 1454 void 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 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* 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 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 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