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")) 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 u1int have; 1020 ulong a, b; 1021 1022 aux = r->fid->aux; 1023 a = 0; 1024 switch(r->ifcall.mode&OMASK){ 1025 case OREAD: 1026 a = 1; 1027 break; 1028 case OWRITE: 1029 a = 2; 1030 break; 1031 case ORDWR: 1032 a = 3; 1033 break; 1034 case OEXEC: 1035 a = 0x20; 1036 break; 1037 } 1038 if(r->ifcall.mode&OTRUNC) 1039 a = 0x10; 1040 1041 if(nfsAccess(aux->auth, r->tag, &aux->handle, a, &b, &have, &attr) < 0 1042 || (!have && nfsGetattr(aux->auth, r->tag, &aux->handle, &attr) < 0)){ 1043 responderrstr(r); 1044 return; 1045 } 1046 attrToQid(&attr, &r->fid->qid); 1047 r->ofcall.qid = r->fid->qid; 1048 respond(r, nil); 1049 } 1050 1051 void 1052 fscreate(Req *r) 1053 { 1054 FidAux *aux; 1055 u1int have; 1056 Nfs3Attr attr; 1057 Nfs3Handle h; 1058 ulong mode; 1059 uint gid; 1060 int (*mk)(Auth*, ulong, Nfs3Handle*, char*, Nfs3Handle*, ulong, uint, u1int*, Nfs3Attr*); 1061 1062 aux = r->fid->aux; 1063 1064 /* 1065 * Plan 9 has no umask, so let's use the 1066 * parent directory bits like Plan 9 does. 1067 * What the heck, let's inherit the group too. 1068 * (Unix will let us set the group to anything 1069 * since we're the owner!) 1070 */ 1071 if(nfsGetattr(aux->auth, r->tag, &aux->handle, &attr) < 0){ 1072 responderrstr(r); 1073 return; 1074 } 1075 mode = r->ifcall.perm&0777; 1076 if(r->ifcall.perm&DMDIR) 1077 mode &= (attr.mode&0666) | ~0666; 1078 else 1079 mode &= (attr.mode&0777) | ~0777; 1080 gid = attr.gid; 1081 1082 if(r->ifcall.perm&DMDIR) 1083 mk = nfsMkdir; 1084 else 1085 mk = nfsCreate; 1086 1087 if((*mk)(aux->auth, r->tag, &aux->handle, r->ifcall.name, &h, mode, gid, &have, &attr) < 0 1088 || (!have && nfsGetattr(aux->auth, r->tag, &h, &attr) < 0)){ 1089 responderrstr(r); 1090 return; 1091 } 1092 attrToQid(&attr, &r->fid->qid); 1093 aux->parent = aux->handle; 1094 aux->handle = h; 1095 free(aux->name); 1096 aux->name = estrdup9p(r->ifcall.name); 1097 r->ofcall.qid = r->fid->qid; 1098 respond(r, nil); 1099 } 1100 1101 void 1102 fsreaddir(Req *r) 1103 { 1104 FidAux *aux; 1105 uchar *p, *freeme, *ep, *p9, *ep9; 1106 uint count; 1107 int n, (*unpack)(uchar*, uchar*, uchar**, Nfs3Entry*); 1108 Nfs3Entry e; 1109 u64int cookie; 1110 Dir d; 1111 1112 aux = r->fid->aux; 1113 /* 1114 * r->ifcall.count seems a reasonable estimate to 1115 * how much NFS entry data we want. is it? 1116 */ 1117 if(r->ifcall.offset) 1118 cookie = aux->cookie; 1119 else 1120 cookie = 0; 1121 if(nfsReadDir(aux->auth, r->tag, &aux->handle, r->ifcall.count, cookie, 1122 &p, &count, &unpack, &freeme) < 0){ 1123 responderrstr(r); 1124 return; 1125 } 1126 ep = p+count; 1127 1128 p9 = (uchar*)r->ofcall.data; 1129 ep9 = p9+r->ifcall.count; 1130 1131 /* 1132 * BUG: Issue all of the stat requests in parallel. 1133 */ 1134 while(p < ep && p9 < ep9){ 1135 if((*unpack)(p, ep, &p, &e) < 0) 1136 break; 1137 aux->cookie = e.cookie; 1138 if(strcmp(e.name, ".") == 0 || strcmp(e.name, "..") == 0) 1139 continue; 1140 if(!e.haveAttr && !e.haveHandle) 1141 if(nfsLookup(aux->auth, r->tag, &aux->handle, e.name, &e.handle, &e.haveAttr, &e.attr) < 0) 1142 continue; 1143 if(!e.haveAttr) 1144 if(nfsGetattr(aux->auth, r->tag, &e.handle, &e.attr) < 0) 1145 continue; 1146 memset(&d, 0, sizeof d); 1147 attrToDir(&e.attr, &d); 1148 d.name = e.name; 1149 if((n = convD2M(&d, p9, ep9-p9)) <= BIT16SZ) 1150 break; 1151 p9 += n; 1152 } 1153 free(freeme); 1154 r->ofcall.count = p9 - (uchar*)r->ofcall.data; 1155 respond(r, nil); 1156 } 1157 1158 void 1159 fsread(Req *r) 1160 { 1161 uchar *p, *freeme; 1162 uint count; 1163 FidAux *aux; 1164 1165 if(r->fid->qid.type&QTDIR){ 1166 fsreaddir(r); 1167 return; 1168 } 1169 1170 aux = r->fid->aux; 1171 if(nfsRead(aux->auth, r->tag, &aux->handle, r->ifcall.count, r->ifcall.offset, &p, &count, &freeme) < 0){ 1172 responderrstr(r); 1173 return; 1174 } 1175 r->ofcall.data = (char*)p; 1176 r->ofcall.count = count; 1177 respond(r, nil); 1178 free(freeme); 1179 } 1180 1181 void 1182 fswrite(Req *r) 1183 { 1184 uint count; 1185 FidAux *aux; 1186 1187 aux = r->fid->aux; 1188 if(nfsWrite(aux->auth, r->tag, &aux->handle, (uchar*)r->ifcall.data, r->ifcall.count, r->ifcall.offset, &count) < 0){ 1189 responderrstr(r); 1190 return; 1191 } 1192 r->ofcall.count = count; 1193 respond(r, nil); 1194 } 1195 1196 void 1197 fsremove(Req *r) 1198 { 1199 int n; 1200 FidAux *aux; 1201 1202 aux = r->fid->aux; 1203 if(aux->name == nil){ 1204 respond(r, "nfs3client botch -- don't know parent handle in remove"); 1205 return; 1206 } 1207 if(r->fid->qid.type&QTDIR) 1208 n = nfsRmdir(aux->auth, r->tag, &aux->parent, aux->name); 1209 else 1210 n = nfsRemove(aux->auth, r->tag, &aux->parent, aux->name); 1211 if(n < 0){ 1212 responderrstr(r); 1213 return; 1214 } 1215 respond(r, nil); 1216 } 1217 1218 void 1219 fsstat(Req *r) 1220 { 1221 FidAux *aux; 1222 Nfs3Attr attr; 1223 1224 aux = r->fid->aux; 1225 if(nfsGetattr(aux->auth, r->tag, &aux->handle, &attr) < 0){ 1226 responderrstr(r); 1227 return; 1228 } 1229 memset(&r->d, 0, sizeof r->d); 1230 attrToDir(&attr, &r->d); 1231 r->d.name = estrdup9p(aux->name ? aux->name : "???"); 1232 respond(r, nil); 1233 } 1234 1235 void 1236 fswstat(Req *r) 1237 { 1238 int op, sync; 1239 FidAux *aux; 1240 Nfs3SetAttr attr; 1241 1242 aux = r->fid->aux; 1243 1244 /* Fill out stat first to catch errors */ 1245 op = 0; 1246 sync = 1; 1247 if(~r->d.mode){ 1248 if(r->d.mode&(DMAPPEND|DMEXCL)){ 1249 respond(r, "wstat -- DMAPPEND and DMEXCL bits not supported"); 1250 return; 1251 } 1252 op = 1; 1253 sync = 0; 1254 attr.setMode = 1; 1255 attr.mode = r->d.mode & 0777; 1256 } 1257 if(r->d.uid && r->d.uid[0]){ 1258 attr.setUid = 1; 1259 if(strtouid(r->d.uid, &attr.uid) < 0){ 1260 respond(r, "wstat -- unknown uid"); 1261 return; 1262 } 1263 op = 1; 1264 sync = 0; 1265 } 1266 if(r->d.gid && r->d.gid[0]){ 1267 attr.setGid = 1; 1268 if(strtogid(r->d.gid, &attr.gid) < 0){ 1269 respond(r, "wstat -- unknown gid"); 1270 return; 1271 } 1272 op = 1; 1273 sync = 0; 1274 } 1275 if(~r->d.length){ 1276 attr.setSize = 1; 1277 attr.size = r->d.length; 1278 } 1279 if(~r->d.mtime){ 1280 attr.setMtime = 1; 1281 attr.mtime.sec = r->d.mtime; 1282 } 1283 1284 /* Try rename first because it's more likely to fail (?) */ 1285 if(r->d.name && r->d.name[0]){ 1286 if(aux->name == nil){ 1287 respond(r, "nfsclient botch -- don't know parent handle in rename"); 1288 return; 1289 } 1290 if(nfsRename(aux->auth, r->tag, &aux->parent, aux->name, &aux->parent, r->d.name) < 0){ 1291 responderrstr(r); 1292 return; 1293 } 1294 free(aux->name); 1295 aux->name = estrdup9p(r->d.name); 1296 sync = 0; 1297 } 1298 1299 /* 1300 * Now we have a problem. The rename succeeded 1301 * but the setattr could fail. Sic transit atomicity. 1302 */ 1303 if(op){ 1304 if(nfsSetattr(aux->auth, r->tag, &aux->handle, &attr) < 0){ 1305 responderrstr(r); 1306 return; 1307 } 1308 } 1309 1310 if(sync){ 1311 /* NFS commit */ 1312 if(nfsCommit(aux->auth, r->tag, &aux->handle) < 0){ 1313 responderrstr(r); 1314 return; 1315 } 1316 } 1317 1318 respond(r, nil); 1319 } 1320 1321 char* 1322 fswalk1(Fid *fid, char *name, void *v) 1323 { 1324 u1int have; 1325 ulong tag; 1326 FidAux *aux; 1327 Nfs3Attr attr; 1328 Nfs3Handle h; 1329 1330 tag = *(ulong*)v; 1331 aux = fid->aux; 1332 1333 if(nfsLookup(aux->auth, tag, &aux->handle, name, &h, &have, &attr) < 0 1334 || (!have && nfsGetattr(aux->auth, tag, &h, &attr) < 0)){ 1335 rerrstr(aux->err, sizeof aux->err); 1336 return aux->err; 1337 } 1338 1339 aux->parent = aux->handle; 1340 aux->handle = h; 1341 free(aux->name); 1342 if(strcmp(name, "..") == 0) 1343 aux->name = nil; 1344 else 1345 aux->name = estrdup9p(name); 1346 attrToQid(&attr, &fid->qid); 1347 return nil; 1348 } 1349 1350 char* 1351 fsclone(Fid *fid, Fid *newfid, void*) 1352 { 1353 FidAux *a, *na; 1354 1355 a = fid->aux; 1356 na = emalloc9p(sizeof(FidAux)); 1357 *na = *a; 1358 if(na->name) 1359 na->name = estrdup9p(na->name); 1360 newfid->aux = na; 1361 if(na->auth) 1362 na->auth->ref++; 1363 return nil; 1364 } 1365 1366 void 1367 fswalk(Req *r) 1368 { 1369 walkandclone(r, fswalk1, fsclone, &r->tag); 1370 } 1371 1372 void 1373 fsflush(Req *r) 1374 { 1375 Req *or; 1376 1377 /* 1378 * Send on the flush channel(s). 1379 * The library will make sure the response 1380 * is delayed as necessary. 1381 */ 1382 or = r->oldreq; 1383 if(nfscli) 1384 sendul(nfscli->flushchan, (ulong)or->tag); 1385 if(mntcli) 1386 sendul(mntcli->flushchan, (ulong)or->tag); 1387 respond(r, nil); 1388 } 1389 1390 void 1391 fsdispatch(void *v) 1392 { 1393 Req *r; 1394 1395 r = v; 1396 switch(r->ifcall.type){ 1397 default: respond(r, "unknown type"); break; 1398 case Tattach: fsattach(r); break; 1399 case Topen: fsopen(r); break; 1400 case Tcreate: fscreate(r); break; 1401 case Tread: fsread(r); break; 1402 case Twrite: fswrite(r); break; 1403 case Tremove: fsremove(r); break; 1404 case Tflush: fsflush(r); break; 1405 case Tstat: fsstat(r); break; 1406 case Twstat: fswstat(r); break; 1407 case Twalk: fswalk(r); break; 1408 } 1409 } 1410 1411 void 1412 fsthread(void*) 1413 { 1414 Req *r; 1415 1416 while((r = recvp(fschan)) != nil) 1417 threadcreate(fsdispatch, r, SunStackSize); 1418 } 1419 1420 void 1421 fssend(Req *r) 1422 { 1423 sendp(fschan, r); 1424 } 1425 1426 void 1427 fsdie(Srv*) 1428 { 1429 threadexitsall(nil); 1430 } 1431 1432 Srv fs = 1433 { 1434 .destroyfid = fsdestroyfid, 1435 .attach= fssend, 1436 .open= fssend, 1437 .create= fssend, 1438 .read= fssend, 1439 .write= fssend, 1440 .remove= fssend, 1441 .flush= fssend, 1442 .stat= fssend, 1443 .wstat= fssend, 1444 .walk= fssend, 1445 .end= fsdie 1446 }; 1447 1448 void 1449 usage(void) 1450 { 1451 fprint(2, "usage: nfs [-DRv] [-p perm] [-s srvname] [-u passwd group] addr [addr]\n"); 1452 fprint(2, "\taddr - address of portmapper server\n"); 1453 fprint(2, "\taddr addr - addresses of mount server and nfs server\n"); 1454 exits("usage"); 1455 } 1456 1457 char* 1458 netchangeport(char *addr, uint port, char *buf, uint nbuf) 1459 { 1460 char *r; 1461 1462 strecpy(buf, buf+nbuf, addr); 1463 r = strrchr(buf, '!'); 1464 if(r == nil) 1465 return nil; 1466 r++; 1467 seprint(r, buf+nbuf, "%ud", port); 1468 return buf; 1469 } 1470 1471 char mbuf[256], nbuf[256]; 1472 char *mountaddr, *nfsaddr; 1473 Channel *csync; 1474 int chattyrpc; 1475 void dialproc(void*); 1476 1477 void 1478 threadmain(int argc, char **argv) 1479 { 1480 char *srvname, *passwd, *group, *addr, *p; 1481 SunClient *cli; 1482 int proto; 1483 uint mport, nport; 1484 ulong perm; 1485 Dir d; 1486 1487 perm = 0600; 1488 passwd = nil; 1489 group = nil; 1490 srvname = nil; 1491 sys = sysname(); 1492 if(sys == nil) 1493 sys = "plan9"; 1494 ARGBEGIN{ 1495 default: 1496 usage(); 1497 case 'D': 1498 chatty9p++; 1499 break; 1500 case 'R': 1501 chattyrpc++; 1502 break; 1503 case 'p': 1504 perm = strtol(EARGF(usage()), &p, 8); 1505 if(perm==0 || *p != 0) 1506 usage(); 1507 break; 1508 case 's': 1509 srvname = EARGF(usage()); 1510 break; 1511 case 'u': 1512 passwd = EARGF(usage()); 1513 group = EARGF(usage()); 1514 break; 1515 case 'v': 1516 verbose++; 1517 break; 1518 }ARGEND 1519 1520 if(argc != 1 && argc != 2) 1521 usage(); 1522 1523 if(srvname == nil) 1524 srvname = argv[0]; 1525 1526 fmtinstall('B', sunRpcFmt); 1527 fmtinstall('C', sunCallFmt); 1528 fmtinstall('H', encodefmt); 1529 sunFmtInstall(&portProg); 1530 sunFmtInstall(&nfs3Prog); 1531 sunFmtInstall(&nfsMount3Prog); 1532 1533 if(passwd && (map = readmap(passwd, group)) == nil) 1534 fprint(2, "warning: reading %s and %s: %r\n", passwd, group); 1535 1536 if(map == nil) 1537 map = &emptymap; 1538 1539 if(argc == 1){ 1540 addr = netmkaddr(argv[0], "udp", "portmap"); 1541 if((cli = sunDial(addr)) == nil) 1542 sysfatal("dial %s: %r", addr); 1543 cli->chatty = chattyrpc; 1544 sunClientProg(cli, &portProg); 1545 if(strstr(addr, "udp!")) 1546 proto = PortProtoUdp; 1547 else 1548 proto = PortProtoTcp; 1549 if(getport(cli, NfsMount3Program, NfsMount3Version, proto, &mport) < 0) 1550 sysfatal("lookup mount program port: %r"); 1551 if(getport(cli, Nfs3Program, Nfs3Version, proto, &nport) < 0) 1552 sysfatal("lookup nfs program port: %r"); 1553 sunClientClose(cli); 1554 mountaddr = netchangeport(addr, mport, mbuf, sizeof mbuf); 1555 nfsaddr = netchangeport(addr, nport, nbuf, sizeof nbuf); 1556 strcat(mountaddr, "!r"); 1557 strcat(nfsaddr, "!r"); 1558 if(verbose) 1559 fprint(2, "nfs %s %s\n", mountaddr, nfsaddr); 1560 }else{ 1561 mountaddr = argv[0]; 1562 nfsaddr = argv[1]; 1563 } 1564 1565 /* have to dial in another proc because it creates threads */ 1566 csync = chancreate(sizeof(void*), 0); 1567 proccreate(dialproc, nil, SunStackSize); 1568 recvp(csync); 1569 1570 threadpostmountsrv(&fs, srvname, nil, 0); 1571 if(perm != 0600){ 1572 p = smprint("/srv/%s", srvname); 1573 if(p){ 1574 nulldir(&d); 1575 d.mode = perm; 1576 dirwstat(p, &d); 1577 } 1578 } 1579 threadexits(nil); 1580 } 1581 1582 void 1583 dialproc(void*) 1584 { 1585 rfork(RFNAMEG); 1586 rfork(RFNOTEG); 1587 if((mntcli = sunDial(mountaddr)) == nil) 1588 sysfatal("dial mount program at %s: %r", mountaddr); 1589 mntcli->chatty = chattyrpc; 1590 sunClientProg(mntcli, &nfsMount3Prog); 1591 if(mountNull(0) < 0) 1592 sysfatal("execute nop with mnt server at %s: %r", mountaddr); 1593 1594 if((nfscli = sunDial(nfsaddr)) == nil) 1595 sysfatal("dial nfs program at %s: %r", nfsaddr); 1596 nfscli->chatty = chattyrpc; 1597 sunClientProg(nfscli, &nfs3Prog); 1598 if(nfsNull(0) < 0) 1599 sysfatal("execute nop with nfs server at %s: %r", nfsaddr); 1600 1601 fschan = chancreate(sizeof(Req*), 0); 1602 threadcreate(fsthread, nil, SunStackSize); 1603 sendp(csync, 0); 1604 } 1605