1 #include "u.h" 2 #include "lib.h" 3 #include "dat.h" 4 #include "fns.h" 5 #include "error.h" 6 7 Chan* 8 fdtochan(int fd, int mode, int chkmnt, int iref) 9 { 10 Fgrp *f; 11 Chan *c; 12 13 c = 0; 14 f = up->fgrp; 15 16 lock(&f->ref.lk); 17 if(fd<0 || NFD<=fd || (c = f->fd[fd])==0) { 18 unlock(&f->ref.lk); 19 error(Ebadfd); 20 } 21 if(iref) 22 refinc(&c->ref); 23 unlock(&f->ref.lk); 24 25 if(chkmnt && (c->flag&CMSG)) 26 goto bad; 27 if(mode<0 || c->mode==ORDWR) 28 return c; 29 if((mode&OTRUNC) && c->mode==OREAD) 30 goto bad; 31 if((mode&~OTRUNC) != c->mode) 32 goto bad; 33 return c; 34 bad: 35 if(iref) 36 cclose(c); 37 error(Ebadusefd); 38 return nil; /* shut up compiler */ 39 } 40 41 static void 42 fdclose(int fd, int flag) 43 { 44 int i; 45 Chan *c; 46 Fgrp *f; 47 48 f = up->fgrp; 49 50 lock(&f->ref.lk); 51 c = f->fd[fd]; 52 if(c == 0) { 53 unlock(&f->ref.lk); 54 return; 55 } 56 if(flag) { 57 if(c==0 || !(c->flag&flag)) { 58 unlock(&f->ref.lk); 59 return; 60 } 61 } 62 f->fd[fd] = 0; 63 if(fd == f->maxfd) 64 for(i=fd; --i>=0 && f->fd[i]==0; ) 65 f->maxfd = i; 66 67 unlock(&f->ref.lk); 68 cclose(c); 69 } 70 71 static int 72 newfd(Chan *c) 73 { 74 int i; 75 Fgrp *f; 76 77 f = up->fgrp; 78 lock(&f->ref.lk); 79 for(i=0; i<NFD; i++) 80 if(f->fd[i] == 0){ 81 if(i > f->maxfd) 82 f->maxfd = i; 83 f->fd[i] = c; 84 unlock(&f->ref.lk); 85 return i; 86 } 87 unlock(&f->ref.lk); 88 error("no file descriptors"); 89 return 0; 90 } 91 92 int 93 sysclose(int fd) 94 { 95 if(waserror()) 96 return -1; 97 98 fdtochan(fd, -1, 0, 0); 99 fdclose(fd, 0); 100 poperror(); 101 return 0; 102 } 103 104 int 105 syscreate(char *path, int mode, ulong perm) 106 { 107 int fd; 108 Chan *c = 0; 109 110 if(waserror()) { 111 cclose(c); 112 return -1; 113 } 114 115 openmode(mode); /* error check only */ 116 c = namec(path, Acreate, mode, perm); 117 fd = newfd((Chan*)c); 118 poperror(); 119 return fd; 120 } 121 122 int 123 sysdup(int old, int new) 124 { 125 Chan *oc; 126 Fgrp *f = up->fgrp; 127 Chan *c = 0; 128 129 if(waserror()) 130 return -1; 131 132 c = fdtochan(old, -1, 0, 1); 133 if(new != -1) { 134 if(new < 0 || NFD <= new) { 135 cclose(c); 136 error(Ebadfd); 137 } 138 lock(&f->ref.lk); 139 if(new > f->maxfd) 140 f->maxfd = new; 141 oc = f->fd[new]; 142 f->fd[new] = (Chan*)c; 143 unlock(&f->ref.lk); 144 if(oc != 0) 145 cclose(oc); 146 } 147 else { 148 if(waserror()) { 149 cclose(c); 150 nexterror(); 151 } 152 new = newfd((Chan*)c); 153 poperror(); 154 } 155 poperror(); 156 return new; 157 } 158 159 int 160 sysfstat(int fd, char *buf) 161 { 162 Chan *c = 0; 163 164 if(waserror()) { 165 cclose(c); 166 return -1; 167 } 168 c = fdtochan(fd, -1, 0, 1); 169 devtab[c->type]->stat((Chan*)c, buf); 170 poperror(); 171 cclose(c); 172 return 0; 173 } 174 175 int 176 sysfwstat(int fd, char *buf) 177 { 178 Chan *c = 0; 179 180 if(waserror()) { 181 cclose(c); 182 return -1; 183 } 184 nameok(buf); 185 c = fdtochan(fd, -1, 1, 1); 186 devtab[c->type]->wstat((Chan*)c, buf); 187 poperror(); 188 cclose(c); 189 return 0; 190 } 191 192 int 193 syschdir(char *dir) 194 { 195 return 0; 196 } 197 198 long 199 bindmount(Chan *c0, char *old, int flag, char *spec) 200 { 201 int ret; 202 Chan *c1 = 0; 203 204 if(flag>MMASK || (flag&MORDER) == (MBEFORE|MAFTER)) 205 error(Ebadarg); 206 207 c1 = namec(old, Amount, 0, 0); 208 if(waserror()){ 209 cclose(c1); 210 nexterror(); 211 } 212 213 ret = cmount(c0, c1, flag, spec); 214 215 poperror(); 216 cclose(c1); 217 return ret; 218 } 219 220 int 221 sysbind(char *new, char *old, int flags) 222 { 223 long r; 224 Chan *c0 = 0; 225 226 if(waserror()) { 227 cclose(c0); 228 return -1; 229 } 230 c0 = namec(new, Aaccess, 0, 0); 231 r = bindmount(c0, old, flags, ""); 232 poperror(); 233 cclose(c0); 234 return 0; 235 } 236 237 int 238 sysmount(int fd, char *old, int flags, char *spec) 239 { 240 long r; 241 Chan *c0 = 0, *bc = 0; 242 struct { 243 Chan* chan; 244 char* spec; 245 int flags; 246 } mntparam; 247 248 if(waserror()) { 249 cclose(bc); 250 cclose(c0); 251 return -1; 252 } 253 bc = fdtochan(fd, ORDWR, 0, 1); 254 mntparam.chan = (Chan*)bc; 255 mntparam.spec = spec; 256 mntparam.flags = flags; 257 c0 = (*devtab[devno('M', 0)].attach)(&mntparam); 258 cclose(bc); 259 r = bindmount(c0, old, flags, spec); 260 poperror(); 261 cclose(c0); 262 263 return r; 264 } 265 266 int 267 sysunmount(char *old, char *new) 268 { 269 Chan *cmount = 0, *cmounted = 0; 270 271 if(waserror()) { 272 cclose(cmount); 273 cclose(cmounted); 274 return -1; 275 } 276 277 cmount = namec(new, Amount, OREAD, 0); 278 if(old != 0) 279 cmounted = namec(old, Aopen, OREAD, 0); 280 281 cunmount(cmount, cmounted); 282 poperror(); 283 cclose(cmount); 284 cclose(cmounted); 285 return 0; 286 } 287 288 int 289 sysopen(char *path, int mode) 290 { 291 int fd; 292 Chan *c = 0; 293 294 if(waserror()){ 295 cclose(c); 296 return -1; 297 } 298 openmode(mode); /* error check only */ 299 c = namec(path, Aopen, mode, 0); 300 fd = newfd((Chan*)c); 301 poperror(); 302 return fd; 303 } 304 305 long 306 unionread(Chan *c, void *va, long n) 307 { 308 long nr; 309 Chan *nc = 0; 310 Pgrp *pg = 0; 311 312 pg = up->pgrp; 313 rlock(&pg->ns); 314 315 for(;;) { 316 if(waserror()) { 317 runlock(&pg->ns); 318 nexterror(); 319 } 320 nc = clone(c->mnt->to, 0); 321 poperror(); 322 323 if(c->mountid != c->mnt->mountid) { 324 runlock(&pg->ns); 325 cclose(nc); 326 return 0; 327 } 328 329 /* Error causes component of union to be skipped */ 330 if(waserror()) { 331 cclose(nc); 332 goto next; 333 } 334 335 nc = (*devtab[nc->type].open)((Chan*)nc, OREAD); 336 nc->offset = c->offset; 337 nr = (*devtab[nc->type].read)((Chan*)nc, va, n, nc->offset); 338 /* devdirread e.g. changes it */ 339 c->offset = nc->offset; 340 poperror(); 341 342 cclose(nc); 343 if(nr > 0) { 344 runlock(&pg->ns); 345 return nr; 346 } 347 /* Advance to next element */ 348 next: 349 c->mnt = c->mnt->next; 350 if(c->mnt == 0) 351 break; 352 c->mountid = c->mnt->mountid; 353 c->offset = 0; 354 } 355 runlock(&pg->ns); 356 return 0; 357 } 358 359 long 360 sysread(int fd, void *va, long n) 361 { 362 int dir; 363 Lock *cl; 364 Chan *c = 0; 365 366 if(waserror()) { 367 cclose(c); 368 return -1; 369 } 370 c = fdtochan(fd, OREAD, 1, 1); 371 372 dir = c->qid.path&CHDIR; 373 if(dir) { 374 n -= n%DIRLEN; 375 if(c->offset%DIRLEN || n==0) 376 error(Etoosmall); 377 } 378 379 if(dir && c->mnt) 380 n = unionread((Chan*)c, va, n); 381 else 382 n = (*devtab[c->type].read)((Chan*)c, va, n, c->offset); 383 384 cl = (Lock*)&c->r.l; 385 lock(cl); 386 c->offset += n; 387 unlock(cl); 388 389 poperror(); 390 cclose(c); 391 392 return n; 393 } 394 395 int 396 sysremove(char *path) 397 { 398 Chan *c = 0; 399 400 if(waserror()) { 401 if(c != 0) 402 c->type = 0; /* see below */ 403 cclose(c); 404 return -1; 405 } 406 c = namec(path, Aaccess, 0, 0); 407 (*devtab[c->type].remove)((Chan*)c); 408 /* 409 * Remove clunks the fid, but we need to recover the Chan 410 * so fake it up. rootclose() is known to be a nop. 411 */ 412 c->type = 0; 413 poperror(); 414 cclose(c); 415 return 0; 416 } 417 418 long 419 sysseek(int fd, long off, int whence) 420 { 421 Dir dir; 422 Chan *c; 423 char buf[DIRLEN]; 424 425 if(waserror()) 426 return -1; 427 428 c = fdtochan(fd, -1, 1, 0); 429 if(c->qid.path & CHDIR) 430 error(Eisdir); 431 432 switch(whence) { 433 case 0: 434 c->offset = off; 435 break; 436 437 case 1: 438 lock(&c->r.l); /* lock for read/write update */ 439 c->offset += off; 440 off = c->offset; 441 unlock(&c->r.l); 442 break; 443 444 case 2: 445 (*devtab[c->type].stat)(c, buf); 446 convM2D(buf, &dir); 447 c->offset = dir.length + off; 448 off = c->offset; 449 break; 450 } 451 poperror(); 452 return off; 453 } 454 455 int 456 sysstat(char *path, char *buf) 457 { 458 Chan *c = 0; 459 460 if(waserror()){ 461 cclose(c); 462 return -1; 463 } 464 c = namec(path, Aaccess, 0, 0); 465 (*devtab[c->type].stat)((Chan*)c, buf); 466 poperror(); 467 cclose(c); 468 return 0; 469 } 470 471 long 472 syswrite(int fd, void *va, long n) 473 { 474 Lock *cl; 475 Chan *c = 0; 476 477 if(waserror()) { 478 cclose(c); 479 return -1; 480 } 481 c = fdtochan(fd, OWRITE, 1, 1); 482 if(c->qid.path & CHDIR) 483 error(Eisdir); 484 485 n = (*devtab[c->type].write)((Chan*)c, va, n, c->offset); 486 487 cl = (Lock*)&c->r.l; 488 lock(cl); 489 c->offset += n; 490 unlock(cl); 491 492 poperror(); 493 cclose(c); 494 495 return n; 496 } 497 498 int 499 syswstat(char *path, char *buf) 500 { 501 Chan *c = 0; 502 503 if(waserror()) { 504 cclose(c); 505 return -1; 506 } 507 508 nameok(buf); 509 c = namec(path, Aaccess, 0, 0); 510 (*devtab[c->type].wstat)((Chan*)c, buf); 511 poperror(); 512 cclose(c); 513 return 0; 514 } 515 516 int 517 sysdirstat(char *name, Dir *dir) 518 { 519 char buf[DIRLEN]; 520 521 if(sysstat(name, buf) == -1) 522 return -1; 523 convM2D(buf, dir); 524 return 0; 525 } 526 527 int 528 sysdirfstat(int fd, Dir *dir) 529 { 530 char buf[DIRLEN]; 531 532 if(sysfstat(fd, buf) == -1) 533 return -1; 534 535 convM2D(buf, dir); 536 return 0; 537 } 538 539 int 540 sysdirwstat(char *name, Dir *dir) 541 { 542 char buf[DIRLEN]; 543 544 convD2M(dir, buf); 545 return syswstat(name, buf); 546 } 547 548 int 549 sysdirfwstat(int fd, Dir *dir) 550 { 551 char buf[DIRLEN]; 552 553 convD2M(dir, buf); 554 return sysfwstat(fd, buf); 555 } 556 557 long 558 sysdirread(int fd, Dir *dbuf, long count) 559 { 560 int c, n, i, r; 561 char buf[DIRLEN*50]; 562 563 n = 0; 564 count = (count/sizeof(Dir)) * DIRLEN; 565 while(n < count) { 566 c = count - n; 567 if(c > sizeof(buf)) 568 c = sizeof(buf); 569 r = sysread(fd, buf, c); 570 if(r == 0) 571 break; 572 if(r < 0 || r % DIRLEN) 573 return -1; 574 for(i=0; i<r; i+=DIRLEN) { 575 convM2D(buf+i, dbuf); 576 dbuf++; 577 } 578 n += r; 579 if(r != c) 580 break; 581 } 582 583 return (n/DIRLEN) * sizeof(Dir); 584 } 585 586 static int 587 call(char *clone, char *dest, int *cfdp, char *dir, char *local) 588 { 589 int fd, cfd, n; 590 char *p, name[3*NAMELEN+5], data[3*NAMELEN+10]; 591 592 cfd = sysopen(clone, ORDWR); 593 if(cfd < 0){ 594 werrstr("%s: %r", clone); 595 return -1; 596 } 597 598 /* get directory name */ 599 n = sysread(cfd, name, sizeof(name)-1); 600 if(n < 0) { 601 sysclose(cfd); 602 return -1; 603 } 604 name[n] = 0; 605 sprint(name, "%d", strtoul(name, 0, 0)); 606 p = strrchr(clone, '/'); 607 *p = 0; 608 if(dir) 609 snprint(dir, 2*NAMELEN, "%s/%s", clone, name); 610 snprint(data, sizeof(data), "%s/%s/data", clone, name); 611 612 /* connect */ 613 /* set local side (port number, for example) if we need to */ 614 if(local) 615 snprint(name, sizeof(name), "connect %s %s", dest, local); 616 else 617 snprint(name, sizeof(name), "connect %s", dest); 618 if(syswrite(cfd, name, strlen(name)) < 0){ 619 werrstr("%s failed: %r", name); 620 sysclose(cfd); 621 return -1; 622 } 623 624 /* open data connection */ 625 fd = sysopen(data, ORDWR); 626 if(fd < 0){ 627 werrstr("can't open %s: %r", data); 628 sysclose(cfd); 629 return -1; 630 } 631 if(cfdp) 632 *cfdp = cfd; 633 else 634 sysclose(cfd); 635 return fd; 636 } 637 638 int 639 sysdial(char *dest, char *local, char *dir, int *cfdp) 640 { 641 int n, fd, rv; 642 char *p, net[128], clone[NAMELEN+12]; 643 644 /* go for a standard form net!... */ 645 p = strchr(dest, '!'); 646 if(p == 0){ 647 snprint(net, sizeof(net), "net!%s", dest); 648 } else { 649 strncpy(net, dest, sizeof(net)-1); 650 net[sizeof(net)-1] = 0; 651 } 652 653 /* call the connection server */ 654 fd = sysopen("/net/cs", ORDWR); 655 if(fd < 0){ 656 /* no connection server, don't translate */ 657 p = strchr(net, '!'); 658 *p++ = 0; 659 snprint(clone, sizeof(clone), "/net/%s/clone", net); 660 return call(clone, p, cfdp, dir, local); 661 } 662 663 /* 664 * send dest to connection to translate 665 */ 666 if(syswrite(fd, net, strlen(net)) < 0){ 667 werrstr("%s: %r", net); 668 sysclose(fd); 669 return -1; 670 } 671 672 /* 673 * loop through each address from the connection server till 674 * we get one that works. 675 */ 676 rv = -1; 677 sysseek(fd, 0, 0); 678 while((n = sysread(fd, net, sizeof(net) - 1)) > 0){ 679 net[n] = 0; 680 p = strchr(net, ' '); 681 if(p == 0) 682 continue; 683 *p++ = 0; 684 rv = call(net, p, cfdp, dir, local); 685 if(rv >= 0) 686 break; 687 } 688 sysclose(fd); 689 return rv; 690 } 691 692 static int 693 identtrans(char *addr, char *naddr, int na, char *file, int nf) 694 { 695 char *p; 696 char reply[4*NAMELEN]; 697 698 /* parse the network */ 699 strncpy(reply, addr, sizeof(reply)); 700 reply[sizeof(reply)-1] = 0; 701 p = strchr(reply, '!'); 702 if(p) 703 *p++ = 0; 704 705 sprint(file, "/net/%.*s/clone", na - sizeof("/net//clone"), reply); 706 strncpy(naddr, p, na); 707 naddr[na-1] = 0; 708 return 1; 709 } 710 711 static int 712 nettrans(char *addr, char *naddr, int na, char *file, int nf) 713 { 714 long n; 715 int fd; 716 char *cp; 717 char reply[4*NAMELEN]; 718 719 /* 720 * ask the connection server 721 */ 722 fd = sysopen("/net/cs", ORDWR); 723 if(fd < 0) 724 return identtrans(addr, naddr, na, file, nf); 725 if(syswrite(fd, addr, strlen(addr)) < 0){ 726 sysclose(fd); 727 return -1; 728 } 729 sysseek(fd, 0, 0); 730 n = sysread(fd, reply, sizeof(reply)-1); 731 sysclose(fd); 732 if(n <= 0) 733 return -1; 734 reply[n] = '\0'; 735 736 /* 737 * parse the reply 738 */ 739 cp = strchr(reply, ' '); 740 if(cp == 0) 741 return -1; 742 *cp++ = 0; 743 strncpy(naddr, cp, na); 744 naddr[na-1] = 0; 745 strncpy(file, reply, nf); 746 file[nf-1] = 0; 747 return 0; 748 } 749 750 int 751 sysannounce(char *addr, char *dir) 752 { 753 char *cp; 754 int ctl, n, m; 755 char buf[3*NAMELEN]; 756 char buf2[3*NAMELEN]; 757 char netdir[2*NAMELEN]; 758 char naddr[3*NAMELEN]; 759 760 /* 761 * translate the address 762 */ 763 if(nettrans(addr, naddr, sizeof(naddr), netdir, sizeof(netdir)) < 0){ 764 werrstr("can't translate address"); 765 return -1; 766 } 767 768 /* 769 * get a control channel 770 */ 771 ctl = sysopen(netdir, ORDWR); 772 if(ctl<0){ 773 werrstr("can't open control channel"); 774 return -1; 775 } 776 cp = strrchr(netdir, '/'); 777 *cp = 0; 778 779 /* 780 * find out which line we have 781 */ 782 n = sprint(buf, "%.*s/", 2*NAMELEN+1, netdir); 783 m = sysread(ctl, &buf[n], sizeof(buf)-n-1); 784 if(m <= 0) { 785 sysclose(ctl); 786 werrstr("can't read control file"); 787 return -1; 788 } 789 buf[n+m] = 0; 790 791 /* 792 * make the call 793 */ 794 n = sprint(buf2, "announce %.*s", 2*NAMELEN, naddr); 795 if(syswrite(ctl, buf2, n) != n) { 796 sysclose(ctl); 797 werrstr("announcement fails"); 798 return -1; 799 } 800 801 strcpy(dir, buf); 802 803 return ctl; 804 } 805 806 int 807 syslisten(char *dir, char *newdir) 808 { 809 char *cp; 810 int ctl, n, m; 811 char buf[3*NAMELEN]; 812 813 /* 814 * open listen, wait for a call 815 */ 816 sprint(buf, "%.*s/listen", 2*NAMELEN+1, dir); 817 ctl = sysopen(buf, ORDWR); 818 if(ctl < 0) 819 return -1; 820 821 /* 822 * find out which line we have 823 */ 824 strcpy(buf, dir); 825 cp = strrchr(buf, '/'); 826 *++cp = 0; 827 n = cp-buf; 828 m = sysread(ctl, cp, sizeof(buf) - n - 1); 829 if(n<=0){ 830 sysclose(ctl); 831 return -1; 832 } 833 buf[n+m] = 0; 834 835 strcpy(newdir, buf); 836 return ctl; 837 } 838