sysfile.c (22482B)
1 #include "u.h" 2 #include "lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "error.h" 7 8 /* 9 * The sys*() routines needn't poperror() as they return directly to syscall(). 10 */ 11 12 static void 13 unlockfgrp(Fgrp *f) 14 { 15 int ex; 16 17 ex = f->exceed; 18 f->exceed = 0; 19 unlock(&f->ref.lk); 20 if(ex) 21 pprint("warning: process exceeds %d file descriptors\n", ex); 22 } 23 24 int 25 growfd(Fgrp *f, int fd) /* fd is always >= 0 */ 26 { 27 Chan **newfd, **oldfd; 28 29 if(fd < f->nfd) 30 return 0; 31 if(fd >= f->nfd+DELTAFD) 32 return -1; /* out of range */ 33 /* 34 * Unbounded allocation is unwise; besides, there are only 16 bits 35 * of fid in 9P 36 */ 37 if(f->nfd >= 5000){ 38 Exhausted: 39 print("no free file descriptors\n"); 40 return -1; 41 } 42 newfd = malloc((f->nfd+DELTAFD)*sizeof(Chan*)); 43 if(newfd == 0) 44 goto Exhausted; 45 oldfd = f->fd; 46 memmove(newfd, oldfd, f->nfd*sizeof(Chan*)); 47 f->fd = newfd; 48 free(oldfd); 49 f->nfd += DELTAFD; 50 if(fd > f->maxfd){ 51 if(fd/100 > f->maxfd/100) 52 f->exceed = (fd/100)*100; 53 f->maxfd = fd; 54 } 55 return 1; 56 } 57 58 /* 59 * this assumes that the fgrp is locked 60 */ 61 int 62 findfreefd(Fgrp *f, int start) 63 { 64 int fd; 65 66 for(fd=start; fd<f->nfd; fd++) 67 if(f->fd[fd] == 0) 68 break; 69 if(fd >= f->nfd && growfd(f, fd) < 0) 70 return -1; 71 return fd; 72 } 73 74 int 75 newfd(Chan *c) 76 { 77 int fd; 78 Fgrp *f; 79 80 f = up->fgrp; 81 lock(&f->ref.lk); 82 fd = findfreefd(f, 0); 83 if(fd < 0){ 84 unlockfgrp(f); 85 return -1; 86 } 87 if(fd > f->maxfd) 88 f->maxfd = fd; 89 f->fd[fd] = c; 90 unlockfgrp(f); 91 return fd; 92 } 93 94 int 95 newfd2(int fd[2], Chan *c[2]) 96 { 97 Fgrp *f; 98 99 f = up->fgrp; 100 lock(&f->ref.lk); 101 fd[0] = findfreefd(f, 0); 102 if(fd[0] < 0){ 103 unlockfgrp(f); 104 return -1; 105 } 106 fd[1] = findfreefd(f, fd[0]+1); 107 if(fd[1] < 0){ 108 unlockfgrp(f); 109 return -1; 110 } 111 if(fd[1] > f->maxfd) 112 f->maxfd = fd[1]; 113 f->fd[fd[0]] = c[0]; 114 f->fd[fd[1]] = c[1]; 115 unlockfgrp(f); 116 117 return 0; 118 } 119 120 Chan* 121 fdtochan(int fd, int mode, int chkmnt, int iref) 122 { 123 Chan *c; 124 Fgrp *f; 125 126 c = 0; 127 f = up->fgrp; 128 129 lock(&f->ref.lk); 130 if(fd<0 || f->nfd<=fd || (c = f->fd[fd])==0) { 131 unlock(&f->ref.lk); 132 error(Ebadfd); 133 } 134 if(iref) 135 incref(&c->ref); 136 unlock(&f->ref.lk); 137 138 if(chkmnt && (c->flag&CMSG)) { 139 if(iref) 140 cclose(c); 141 error(Ebadusefd); 142 } 143 144 if(mode<0 || c->mode==ORDWR) 145 return c; 146 147 if((mode&OTRUNC) && c->mode==OREAD) { 148 if(iref) 149 cclose(c); 150 error(Ebadusefd); 151 } 152 153 if((mode&~OTRUNC) != c->mode) { 154 if(iref) 155 cclose(c); 156 error(Ebadusefd); 157 } 158 159 return c; 160 } 161 162 int 163 openmode(ulong o) 164 { 165 o &= ~(OTRUNC|OCEXEC|ORCLOSE); 166 if(o > OEXEC) 167 error(Ebadarg); 168 if(o == OEXEC) 169 return OREAD; 170 return o; 171 } 172 173 long 174 sysfd2path(uint32 *arg) 175 { 176 Chan *c; 177 char *buf; 178 179 buf = uvalidaddr(arg[1], arg[2], 1); 180 181 c = fdtochan(arg[0], -1, 0, 1); 182 snprint(buf, arg[2], "%s", chanpath(c)); 183 cclose(c); 184 return 0; 185 } 186 187 long 188 syspipe(uint32 *arg) 189 { 190 int fd[2]; 191 Chan *c[2]; 192 Dev *d; 193 static char *datastr[] = {"data", "data1"}; 194 int *ufd; 195 196 ufd = uvalidaddr(arg[0], 2*BY2WD, 1); 197 evenaddr(arg[0]); 198 d = devtab[devno('|', 0)]; 199 c[0] = namec("#|", Atodir, 0, 0); 200 c[1] = 0; 201 fd[0] = -1; 202 fd[1] = -1; 203 204 if(waserror()){ 205 cclose(c[0]); 206 if(c[1]) 207 cclose(c[1]); 208 nexterror(); 209 } 210 c[1] = cclone(c[0]); 211 if(walk(&c[0], datastr+0, 1, 1, nil) < 0) 212 error(Egreg); 213 if(walk(&c[1], datastr+1, 1, 1, nil) < 0) 214 error(Egreg); 215 c[0] = d->open(c[0], ORDWR); 216 c[1] = d->open(c[1], ORDWR); 217 if(newfd2(fd, c) < 0) 218 error(Enofd); 219 poperror(); 220 221 ufd[0] = fd[0]; 222 ufd[1] = fd[1]; 223 return 0; 224 } 225 226 long 227 sysdup(uint32 *arg) 228 { 229 int fd; 230 Chan *c, *oc; 231 Fgrp *f = up->fgrp; 232 233 /* 234 * Close after dup'ing, so date > #d/1 works 235 */ 236 c = fdtochan(arg[0], -1, 0, 1); 237 fd = arg[1]; 238 if(fd != -1){ 239 lock(&f->ref.lk); 240 if(fd<0 || growfd(f, fd)<0) { 241 unlockfgrp(f); 242 cclose(c); 243 error(Ebadfd); 244 } 245 if(fd > f->maxfd) 246 f->maxfd = fd; 247 248 oc = f->fd[fd]; 249 f->fd[fd] = c; 250 unlockfgrp(f); 251 if(oc) 252 cclose(oc); 253 }else{ 254 if(waserror()) { 255 cclose(c); 256 nexterror(); 257 } 258 fd = newfd(c); 259 if(fd < 0) 260 error(Enofd); 261 poperror(); 262 } 263 264 return fd; 265 } 266 267 long 268 sysopen(uint32 *arg) 269 { 270 int fd; 271 Chan *c = 0; 272 char *name; 273 274 openmode(arg[1]); /* error check only */ 275 name = uvalidaddr(arg[0], 1, 0); 276 c = namec(name, Aopen, arg[1], 0); 277 if(waserror()){ 278 cclose(c); 279 nexterror(); 280 } 281 fd = newfd(c); 282 if(fd < 0) 283 error(Enofd); 284 poperror(); 285 return fd; 286 } 287 288 void 289 fdclose(int fd, int flag) 290 { 291 int i; 292 Chan *c; 293 Fgrp *f = up->fgrp; 294 295 lock(&f->ref.lk); 296 c = f->fd[fd]; 297 if(c == 0){ 298 /* can happen for users with shared fd tables */ 299 unlock(&f->ref.lk); 300 return; 301 } 302 if(flag){ 303 if(c==0 || !(c->flag&flag)){ 304 unlock(&f->ref.lk); 305 return; 306 } 307 } 308 f->fd[fd] = 0; 309 if(fd == f->maxfd) 310 for(i=fd; --i>=0 && f->fd[i]==0; ) 311 f->maxfd = i; 312 313 unlock(&f->ref.lk); 314 cclose(c); 315 } 316 317 long 318 sysclose(uint32 *arg) 319 { 320 fdtochan(arg[0], -1, 0, 0); 321 fdclose(arg[0], 0); 322 323 return 0; 324 } 325 326 long 327 unionread(Chan *c, void *va, long n) 328 { 329 int i; 330 long nr; 331 Mhead *m; 332 Mount *mount; 333 334 qlock(&c->umqlock); 335 m = c->umh; 336 rlock(&m->lock); 337 mount = m->mount; 338 /* bring mount in sync with c->uri and c->umc */ 339 for(i = 0; mount != nil && i < c->uri; i++) 340 mount = mount->next; 341 342 nr = 0; 343 while(mount != nil){ 344 /* Error causes component of union to be skipped */ 345 if(mount->to && !waserror()){ 346 if(c->umc == nil){ 347 c->umc = cclone(mount->to); 348 c->umc = devtab[c->umc->type]->open(c->umc, OREAD); 349 } 350 351 nr = devtab[c->umc->type]->read(c->umc, va, n, c->umc->offset); 352 c->umc->offset += nr; 353 poperror(); 354 } 355 if(nr > 0) 356 break; 357 358 /* Advance to next element */ 359 c->uri++; 360 if(c->umc){ 361 cclose(c->umc); 362 c->umc = nil; 363 } 364 mount = mount->next; 365 } 366 runlock(&m->lock); 367 qunlock(&c->umqlock); 368 return nr; 369 } 370 371 static void 372 unionrewind(Chan *c) 373 { 374 qlock(&c->umqlock); 375 c->uri = 0; 376 if(c->umc){ 377 cclose(c->umc); 378 c->umc = nil; 379 } 380 qunlock(&c->umqlock); 381 } 382 383 static int 384 dirfixed(uchar *p, uchar *e, Dir *d) 385 { 386 int len; 387 388 len = GBIT16(p)+BIT16SZ; 389 if(p + len > e) 390 return -1; 391 392 p += BIT16SZ; /* ignore size */ 393 d->type = devno(GBIT16(p), 1); 394 p += BIT16SZ; 395 d->dev = GBIT32(p); 396 p += BIT32SZ; 397 d->qid.type = GBIT8(p); 398 p += BIT8SZ; 399 d->qid.vers = GBIT32(p); 400 p += BIT32SZ; 401 d->qid.path = GBIT64(p); 402 p += BIT64SZ; 403 d->mode = GBIT32(p); 404 p += BIT32SZ; 405 d->atime = GBIT32(p); 406 p += BIT32SZ; 407 d->mtime = GBIT32(p); 408 p += BIT32SZ; 409 d->length = GBIT64(p); 410 411 return len; 412 } 413 414 static char* 415 dirname(uchar *p, int *n) 416 { 417 p += BIT16SZ+BIT16SZ+BIT32SZ+BIT8SZ+BIT32SZ+BIT64SZ 418 + BIT32SZ+BIT32SZ+BIT32SZ+BIT64SZ; 419 *n = GBIT16(p); 420 return (char*)p+BIT16SZ; 421 } 422 423 static long 424 dirsetname(char *name, int len, uchar *p, long n, long maxn) 425 { 426 char *oname; 427 int olen; 428 long nn; 429 430 if(n == BIT16SZ) 431 return BIT16SZ; 432 433 oname = dirname(p, &olen); 434 435 nn = n+len-olen; 436 PBIT16(p, nn-BIT16SZ); 437 if(nn > maxn) 438 return BIT16SZ; 439 440 if(len != olen) 441 memmove(oname+len, oname+olen, p+n-(uchar*)(oname+olen)); 442 PBIT16((uchar*)(oname-2), len); 443 memmove(oname, name, len); 444 return nn; 445 } 446 447 /* 448 * Mountfix might have caused the fixed results of the directory read 449 * to overflow the buffer. Catch the overflow in c->dirrock. 450 */ 451 static void 452 mountrock(Chan *c, uchar *p, uchar **pe) 453 { 454 uchar *e, *r; 455 int len, n; 456 457 e = *pe; 458 459 /* find last directory entry */ 460 for(;;){ 461 len = BIT16SZ+GBIT16(p); 462 if(p+len >= e) 463 break; 464 p += len; 465 } 466 467 /* save it away */ 468 qlock(&c->rockqlock); 469 if(c->nrock+len > c->mrock){ 470 n = ROUND(c->nrock+len, 1024); 471 r = smalloc(n); 472 memmove(r, c->dirrock, c->nrock); 473 free(c->dirrock); 474 c->dirrock = r; 475 c->mrock = n; 476 } 477 memmove(c->dirrock+c->nrock, p, len); 478 c->nrock += len; 479 qunlock(&c->rockqlock); 480 481 /* drop it */ 482 *pe = p; 483 } 484 485 /* 486 * Satisfy a directory read with the results saved in c->dirrock. 487 */ 488 static int 489 mountrockread(Chan *c, uchar *op, long n, long *nn) 490 { 491 long dirlen; 492 uchar *rp, *erp, *ep, *p; 493 494 /* common case */ 495 if(c->nrock == 0) 496 return 0; 497 498 /* copy out what we can */ 499 qlock(&c->rockqlock); 500 rp = c->dirrock; 501 erp = rp+c->nrock; 502 p = op; 503 ep = p+n; 504 while(rp+BIT16SZ <= erp){ 505 dirlen = BIT16SZ+GBIT16(rp); 506 if(p+dirlen > ep) 507 break; 508 memmove(p, rp, dirlen); 509 p += dirlen; 510 rp += dirlen; 511 } 512 513 if(p == op){ 514 qunlock(&c->rockqlock); 515 return 0; 516 } 517 518 /* shift the rest */ 519 if(rp != erp) 520 memmove(c->dirrock, rp, erp-rp); 521 c->nrock = erp - rp; 522 523 *nn = p - op; 524 qunlock(&c->rockqlock); 525 return 1; 526 } 527 528 static void 529 mountrewind(Chan *c) 530 { 531 c->nrock = 0; 532 } 533 534 /* 535 * Rewrite the results of a directory read to reflect current 536 * name space bindings and mounts. Specifically, replace 537 * directory entries for bind and mount points with the results 538 * of statting what is mounted there. Except leave the old names. 539 */ 540 static long 541 mountfix(Chan *c, uchar *op, long n, long maxn) 542 { 543 char *name; 544 int nbuf, nname; 545 Chan *nc; 546 Mhead *mh; 547 Mount *m; 548 uchar *p; 549 int dirlen, rest; 550 long l; 551 uchar *buf, *e; 552 Dir d; 553 554 p = op; 555 buf = nil; 556 nbuf = 0; 557 for(e=&p[n]; p+BIT16SZ<e; p+=dirlen){ 558 dirlen = dirfixed(p, e, &d); 559 if(dirlen < 0) 560 break; 561 nc = nil; 562 mh = nil; 563 if(findmount(&nc, &mh, d.type, d.dev, d.qid)){ 564 /* 565 * If it's a union directory and the original is 566 * in the union, don't rewrite anything. 567 */ 568 for(m=mh->mount; m; m=m->next) 569 if(eqchantdqid(m->to, d.type, d.dev, d.qid, 1)) 570 goto Norewrite; 571 572 name = dirname(p, &nname); 573 /* 574 * Do the stat but fix the name. If it fails, leave old entry. 575 * BUG: If it fails because there isn't room for the entry, 576 * what can we do? Nothing, really. Might as well skip it. 577 */ 578 if(buf == nil){ 579 buf = smalloc(4096); 580 nbuf = 4096; 581 } 582 if(waserror()) 583 goto Norewrite; 584 l = devtab[nc->type]->stat(nc, buf, nbuf); 585 l = dirsetname(name, nname, buf, l, nbuf); 586 if(l == BIT16SZ) 587 error("dirsetname"); 588 poperror(); 589 590 /* 591 * Shift data in buffer to accomodate new entry, 592 * possibly overflowing into rock. 593 */ 594 rest = e - (p+dirlen); 595 if(l > dirlen){ 596 while(p+l+rest > op+maxn){ 597 mountrock(c, p, &e); 598 if(e == p){ 599 dirlen = 0; 600 goto Norewrite; 601 } 602 rest = e - (p+dirlen); 603 } 604 } 605 if(l != dirlen){ 606 memmove(p+l, p+dirlen, rest); 607 dirlen = l; 608 e = p+dirlen+rest; 609 } 610 611 /* 612 * Rewrite directory entry. 613 */ 614 memmove(p, buf, l); 615 616 Norewrite: 617 cclose(nc); 618 putmhead(mh); 619 } 620 } 621 if(buf) 622 free(buf); 623 624 if(p != e) 625 error("oops in rockfix"); 626 627 return e-op; 628 } 629 630 static long 631 doread(uint32 *arg, vlong *offp) 632 { 633 int dir; 634 long n, nn, nnn; 635 uchar *p; 636 Chan *c; 637 vlong off; 638 639 n = arg[2]; 640 p = uvalidaddr(arg[1], n, 1); 641 c = fdtochan(arg[0], OREAD, 1, 1); 642 643 if(waserror()){ 644 cclose(c); 645 nexterror(); 646 } 647 648 /* 649 * The offset is passed through on directories, normally. 650 * Sysseek complains, but pread is used by servers like exportfs, 651 * that shouldn't need to worry about this issue. 652 * 653 * Notice that c->devoffset is the offset that c's dev is seeing. 654 * The number of bytes read on this fd (c->offset) may be different 655 * due to rewritings in rockfix. 656 */ 657 if(offp == nil) /* use and maintain channel's offset */ 658 off = c->offset; 659 else 660 off = *offp; 661 if(off < 0) 662 error(Enegoff); 663 664 if(off == 0){ /* rewind to the beginning of the directory */ 665 if(offp == nil){ 666 c->offset = 0; 667 c->devoffset = 0; 668 } 669 mountrewind(c); 670 unionrewind(c); 671 } 672 673 dir = c->qid.type&QTDIR; 674 if(dir && mountrockread(c, p, n, &nn)){ 675 /* do nothing: mountrockread filled buffer */ 676 }else{ 677 if(dir && c->umh) 678 nn = unionread(c, p, n); 679 else 680 nn = devtab[c->type]->read(c, p, n, off); 681 } 682 if(dir) 683 nnn = mountfix(c, p, nn, n); 684 else 685 nnn = nn; 686 687 lock(&c->ref.lk); 688 c->devoffset += nn; 689 c->offset += nnn; 690 unlock(&c->ref.lk); 691 692 poperror(); 693 cclose(c); 694 695 return nnn; 696 } 697 698 long 699 sys_read(uint32 *arg) 700 { 701 return doread(arg, nil); 702 } 703 704 long 705 syspread(uint32 *arg) 706 { 707 vlong v; 708 709 // Plan 9 VX replaced dodgy varargs code 710 v = *(vlong*)&arg[3]; 711 712 if(v == ~0ULL) 713 return doread(arg, nil); 714 715 return doread(arg, &v); 716 } 717 718 static long 719 dowrite(uint32 *arg, vlong *offp) 720 { 721 Chan *c; 722 long m, n; 723 vlong off; 724 uchar *p; 725 726 p = uvalidaddr(arg[1], arg[2], 0); 727 n = 0; 728 c = fdtochan(arg[0], OWRITE, 1, 1); 729 if(waserror()) { 730 if(offp == nil){ 731 lock(&c->ref.lk); 732 c->offset -= n; 733 unlock(&c->ref.lk); 734 } 735 cclose(c); 736 nexterror(); 737 } 738 739 if(c->qid.type & QTDIR) 740 error(Eisdir); 741 742 n = arg[2]; 743 744 if(offp == nil){ /* use and maintain channel's offset */ 745 lock(&c->ref.lk); 746 off = c->offset; 747 c->offset += n; 748 unlock(&c->ref.lk); 749 }else 750 off = *offp; 751 752 if(off < 0) 753 error(Enegoff); 754 755 m = devtab[c->type]->write(c, p, n, off); 756 757 if(offp == nil && m < n){ 758 lock(&c->ref.lk); 759 c->offset -= n - m; 760 unlock(&c->ref.lk); 761 } 762 763 poperror(); 764 cclose(c); 765 766 return m; 767 } 768 769 long 770 sys_write(uint32 *arg) 771 { 772 return dowrite(arg, nil); 773 } 774 775 long 776 syspwrite(uint32 *arg) 777 { 778 vlong v; 779 780 // Plan 9 VX replaced dodgy varargs code 781 v = *(vlong*)&arg[3]; 782 783 if(v == ~0ULL) 784 return dowrite(arg, nil); 785 786 return dowrite(arg, &v); 787 } 788 789 static void 790 sseek(vlong *ret, uint32 *arg) 791 { 792 Chan *c; 793 uchar buf[sizeof(Dir)+100]; 794 Dir dir; 795 int n; 796 vlong off; 797 union { 798 vlong v; 799 uint32 u[2]; 800 } o; 801 802 c = fdtochan(arg[1], -1, 1, 1); 803 if(waserror()){ 804 cclose(c); 805 nexterror(); 806 } 807 if(devtab[c->type]->dc == '|') 808 error(Eisstream); 809 810 off = 0; 811 o.u[0] = arg[2]; 812 o.u[1] = arg[3]; 813 switch(arg[4]){ 814 case 0: 815 off = o.v; 816 if((c->qid.type & QTDIR) && off != 0) 817 error(Eisdir); 818 if(off < 0) 819 error(Enegoff); 820 c->offset = off; 821 break; 822 823 case 1: 824 if(c->qid.type & QTDIR) 825 error(Eisdir); 826 lock(&c->ref.lk); /* lock for read/write update */ 827 off = o.v + c->offset; 828 if(off < 0){ 829 unlock(&c->ref.lk); 830 error(Enegoff); 831 } 832 c->offset = off; 833 unlock(&c->ref.lk); 834 break; 835 836 case 2: 837 if(c->qid.type & QTDIR) 838 error(Eisdir); 839 n = devtab[c->type]->stat(c, buf, sizeof buf); 840 if(convM2D(buf, n, &dir, nil) == 0) 841 error("internal error: stat error in seek"); 842 off = dir.length + o.v; 843 if(off < 0) 844 error(Enegoff); 845 c->offset = off; 846 break; 847 848 default: 849 error(Ebadarg); 850 } 851 *ret = off; 852 c->uri = 0; 853 c->dri = 0; 854 cclose(c); 855 poperror(); 856 } 857 858 long 859 sysseek(uint32 *arg) 860 { 861 sseek(uvalidaddr(arg[0], BY2V, 1), arg); 862 return 0; 863 } 864 865 long 866 sysoseek(uint32 *arg) 867 { 868 union { 869 vlong v; 870 uint32 u[2]; 871 } o; 872 uint32 a[5]; 873 874 o.v = (long)arg[1]; 875 a[0] = 0; 876 a[1] = arg[0]; 877 a[2] = o.u[0]; 878 a[3] = o.u[1]; 879 a[4] = arg[2]; 880 sseek(&o.v, a); 881 return o.v; 882 } 883 884 void 885 validstat(uchar *s, int n) 886 { 887 int m; 888 char buf[64]; 889 890 if(statcheck(s, n) < 0) 891 error(Ebadstat); 892 /* verify that name entry is acceptable */ 893 s += STATFIXLEN - 4*BIT16SZ; /* location of first string */ 894 /* 895 * s now points at count for first string. 896 * if it's too long, let the server decide; this is 897 * only for his protection anyway. otherwise 898 * we'd have to allocate and waserror. 899 */ 900 m = GBIT16(s); 901 s += BIT16SZ; 902 if(m+1 > sizeof buf) 903 return; 904 memmove(buf, s, m); 905 buf[m] = '\0'; 906 /* name could be '/' */ 907 if(strcmp(buf, "/") != 0) 908 validname(buf, 0); 909 } 910 911 static char* 912 pathlast(Path *p) 913 { 914 char *s; 915 916 if(p == nil) 917 return nil; 918 if(p->len == 0) 919 return nil; 920 s = strrchr(p->s, '/'); 921 if(s) 922 return s+1; 923 return p->s; 924 } 925 926 long 927 sysfstat(uint32 *arg) 928 { 929 Chan *c; 930 uint l; 931 uchar *p; 932 933 l = arg[2]; 934 p = uvalidaddr(arg[1], l, 1); 935 c = fdtochan(arg[0], -1, 0, 1); 936 if(waserror()) { 937 cclose(c); 938 nexterror(); 939 } 940 l = devtab[c->type]->stat(c, p, l); 941 poperror(); 942 cclose(c); 943 return l; 944 } 945 946 long 947 sysstat(uint32 *arg) 948 { 949 char *name; 950 Chan *c; 951 uint l; 952 uchar *p; 953 954 l = arg[2]; 955 p = uvalidaddr(arg[1], l, 1); 956 name = uvalidaddr(arg[0], 1, 0); 957 c = namec(name, Aaccess, 0, 0); 958 if(waserror()){ 959 cclose(c); 960 nexterror(); 961 } 962 l = devtab[c->type]->stat(c, p, l); 963 name = pathlast(c->path); 964 if(name) 965 l = dirsetname(name, strlen(name), p, l, arg[2]); 966 967 poperror(); 968 cclose(c); 969 return l; 970 } 971 972 long 973 syschdir(uint32 *arg) 974 { 975 Chan *c; 976 char *name; 977 978 name = uvalidaddr(arg[0], 1, 0); 979 980 c = namec(name, Atodir, 0, 0); 981 cclose(up->dot); 982 up->dot = c; 983 return 0; 984 } 985 986 // Plan 9 VX added isk parameter. 987 long 988 bindmount(int ismount, int fd, int afd, char* arg0, char* arg1, ulong flag, char* spec) 989 { 990 int ret; 991 Chan *c0, *c1, *ac, *bc; 992 struct{ 993 Chan *chan; 994 Chan *authchan; 995 char *spec; 996 int flags; 997 }bogus; 998 999 if((flag&~MMASK) || (flag&MORDER)==(MBEFORE|MAFTER)) 1000 error(Ebadarg); 1001 1002 bogus.flags = flag & MCACHE; 1003 1004 if(ismount){ 1005 if(up->pgrp->noattach) 1006 error(Enoattach); 1007 1008 ac = nil; 1009 bc = fdtochan(fd, ORDWR, 0, 1); 1010 if(waserror()) { 1011 if(ac) 1012 cclose(ac); 1013 cclose(bc); 1014 nexterror(); 1015 } 1016 1017 if(afd >= 0) 1018 ac = fdtochan(afd, ORDWR, 0, 1); 1019 1020 bogus.chan = bc; 1021 bogus.authchan = ac; 1022 1023 bogus.spec = spec; 1024 if(waserror()) 1025 error(Ebadspec); 1026 spec = validnamedup(spec, 1); 1027 poperror(); 1028 1029 if(waserror()){ 1030 free(spec); 1031 nexterror(); 1032 } 1033 1034 ret = devno('M', 0); 1035 c0 = devtab[ret]->attach((char*)&bogus); 1036 1037 poperror(); /* spec */ 1038 free(spec); 1039 poperror(); /* ac bc */ 1040 if(ac) 1041 cclose(ac); 1042 cclose(bc); 1043 }else{ 1044 bogus.spec = 0; 1045 c0 = namec(arg0, Abind, 0, 0); 1046 } 1047 1048 if(waserror()){ 1049 cclose(c0); 1050 nexterror(); 1051 } 1052 1053 c1 = namec(arg1, Amount, 0, 0); 1054 if(waserror()){ 1055 cclose(c1); 1056 nexterror(); 1057 } 1058 1059 ret = cmount(&c0, c1, flag, bogus.spec); 1060 1061 poperror(); 1062 cclose(c1); 1063 poperror(); 1064 cclose(c0); 1065 if(ismount) 1066 fdclose(fd, 0); 1067 1068 return ret; 1069 } 1070 1071 long 1072 sysbind(uint32 *arg) 1073 { 1074 return bindmount(0, -1, -1, uvalidaddr(arg[0], 1, 0), uvalidaddr(arg[1], 1, 0), arg[2], nil); 1075 } 1076 1077 long 1078 sysmount(uint32 *arg) 1079 { 1080 return bindmount(1, arg[0], arg[1], nil, uvalidaddr(arg[2], 1, 0), arg[3], uvalidaddr(arg[4], 1, 0)); 1081 } 1082 1083 long 1084 sys_mount(uint32 *arg) 1085 { 1086 return bindmount(1, arg[0], -1, nil, uvalidaddr(arg[1], 1, 0), arg[2], uvalidaddr(arg[3], 1, 0)); 1087 } 1088 1089 long 1090 sysunmount(uint32 *arg) 1091 { 1092 Chan *cmount, *cmounted; 1093 char *mount, *mounted; 1094 1095 cmounted = 0; 1096 1097 mount = uvalidaddr(arg[1], 1, 0); 1098 cmount = namec(mount, Amount, 0, 0); 1099 1100 if(arg[0]) { 1101 if(waserror()) { 1102 cclose(cmount); 1103 nexterror(); 1104 } 1105 mounted = uvalidaddr(arg[0], 1, 0); 1106 /* 1107 * This has to be namec(..., Aopen, ...) because 1108 * if arg[0] is something like /srv/cs or /fd/0, 1109 * opening it is the only way to get at the real 1110 * Chan underneath. 1111 */ 1112 cmounted = namec(mounted, Aopen, OREAD, 0); 1113 poperror(); 1114 } 1115 1116 if(waserror()) { 1117 cclose(cmount); 1118 if(cmounted) 1119 cclose(cmounted); 1120 nexterror(); 1121 } 1122 1123 cunmount(cmount, cmounted); 1124 cclose(cmount); 1125 if(cmounted) 1126 cclose(cmounted); 1127 poperror(); 1128 return 0; 1129 } 1130 1131 long 1132 syscreate(uint32 *arg) 1133 { 1134 int fd; 1135 Chan *c = 0; 1136 char *name; 1137 1138 openmode(arg[1]&~OEXCL); /* error check only; OEXCL okay here */ 1139 if(waserror()) { 1140 if(c) 1141 cclose(c); 1142 nexterror(); 1143 } 1144 name = uvalidaddr(arg[0], 1, 0); 1145 c = namec(name, Acreate, arg[1], arg[2]); 1146 fd = newfd(c); 1147 if(fd < 0) 1148 error(Enofd); 1149 poperror(); 1150 return fd; 1151 } 1152 1153 long 1154 sysremove(uint32 *arg) 1155 { 1156 Chan *c; 1157 char *name; 1158 1159 name = uvalidaddr(arg[0], 1, 0); 1160 c = namec(name, Aremove, 0, 0); 1161 /* 1162 * Removing mount points is disallowed to avoid surprises 1163 * (which should be removed: the mount point or the mounted Chan?). 1164 */ 1165 if(c->ismtpt){ 1166 cclose(c); 1167 error(Eismtpt); 1168 } 1169 if(waserror()){ 1170 c->type = 0; /* see below */ 1171 cclose(c); 1172 nexterror(); 1173 } 1174 devtab[c->type]->remove(c); 1175 /* 1176 * Remove clunks the fid, but we need to recover the Chan 1177 * so fake it up. rootclose() is known to be a nop. 1178 */ 1179 c->type = 0; 1180 poperror(); 1181 cclose(c); 1182 return 0; 1183 } 1184 1185 static long 1186 wstat(Chan *c, uchar *d, int nd) 1187 { 1188 long l; 1189 int namelen; 1190 1191 if(waserror()){ 1192 cclose(c); 1193 nexterror(); 1194 } 1195 if(c->ismtpt){ 1196 /* 1197 * Renaming mount points is disallowed to avoid surprises 1198 * (which should be renamed? the mount point or the mounted Chan?). 1199 */ 1200 dirname(d, &namelen); 1201 if(namelen) 1202 nameerror(chanpath(c), Eismtpt); 1203 } 1204 l = devtab[c->type]->wstat(c, d, nd); 1205 poperror(); 1206 cclose(c); 1207 return l; 1208 } 1209 1210 long 1211 syswstat(uint32 *arg) 1212 { 1213 Chan *c; 1214 uint l; 1215 char *name; 1216 uchar *p; 1217 1218 l = arg[2]; 1219 p = uvalidaddr(arg[1], l, 0); 1220 validstat(p, l); 1221 name = uvalidaddr(arg[0], 1, 0); 1222 c = namec(name, Aaccess, 0, 0); 1223 return wstat(c, p, l); 1224 } 1225 1226 long 1227 sysfwstat(uint32 *arg) 1228 { 1229 Chan *c; 1230 uint l; 1231 uchar *p; 1232 1233 l = arg[2]; 1234 p = uvalidaddr(arg[1], l, 0); 1235 validstat(p, l); 1236 c = fdtochan(arg[0], -1, 1, 1); 1237 return wstat(c, p, l); 1238 } 1239 1240 static void 1241 packoldstat(uchar *buf, Dir *d) 1242 { 1243 uchar *p; 1244 ulong q; 1245 1246 /* lay down old stat buffer - grotty code but it's temporary */ 1247 p = buf; 1248 strncpy((char*)p, d->name, 28); 1249 p += 28; 1250 strncpy((char*)p, d->uid, 28); 1251 p += 28; 1252 strncpy((char*)p, d->gid, 28); 1253 p += 28; 1254 q = d->qid.path & ~DMDIR; /* make sure doesn't accidentally look like directory */ 1255 if(d->qid.type & QTDIR) /* this is the real test of a new directory */ 1256 q |= DMDIR; 1257 PBIT32(p, q); 1258 p += BIT32SZ; 1259 PBIT32(p, d->qid.vers); 1260 p += BIT32SZ; 1261 PBIT32(p, d->mode); 1262 p += BIT32SZ; 1263 PBIT32(p, d->atime); 1264 p += BIT32SZ; 1265 PBIT32(p, d->mtime); 1266 p += BIT32SZ; 1267 PBIT64(p, d->length); 1268 p += BIT64SZ; 1269 PBIT16(p, d->type); 1270 p += BIT16SZ; 1271 PBIT16(p, d->dev); 1272 } 1273 1274 long 1275 sys_stat(uint32 *arg) 1276 { 1277 Chan *c; 1278 uint l; 1279 uchar buf[128]; /* old DIRLEN plus a little should be plenty */ 1280 char strs[128], *name, *elem; 1281 Dir d; 1282 char old[] = "old stat system call - recompile"; 1283 uchar *p; 1284 1285 p = uvalidaddr(arg[1], 116, 1); 1286 name = uvalidaddr(arg[0], 1, 0); 1287 c = namec(name, Aaccess, 0, 0); 1288 if(waserror()){ 1289 cclose(c); 1290 nexterror(); 1291 } 1292 l = devtab[c->type]->stat(c, buf, sizeof buf); 1293 /* buf contains a new stat buf; convert to old. yuck. */ 1294 if(l <= BIT16SZ) /* buffer too small; time to face reality */ 1295 error(old); 1296 elem = pathlast(c->path); 1297 if(elem) 1298 l = dirsetname(elem, strlen(elem), buf, l, sizeof buf); 1299 l = convM2D(buf, l, &d, strs); 1300 if(l == 0) 1301 error(old); 1302 packoldstat(p, &d); 1303 1304 poperror(); 1305 cclose(c); 1306 return 0; 1307 } 1308 1309 long 1310 sys_fstat(uint32 *arg) 1311 { 1312 Chan *c; 1313 char *name; 1314 uint l; 1315 uchar buf[128]; /* old DIRLEN plus a little should be plenty */ 1316 char strs[128]; 1317 Dir d; 1318 char old[] = "old fstat system call - recompile"; 1319 uchar *p; 1320 1321 p = uvalidaddr(arg[1], 116, 1); 1322 c = fdtochan(arg[0], -1, 0, 1); 1323 if(waserror()){ 1324 cclose(c); 1325 nexterror(); 1326 } 1327 l = devtab[c->type]->stat(c, buf, sizeof buf); 1328 /* buf contains a new stat buf; convert to old. yuck. */ 1329 if(l <= BIT16SZ) /* buffer too small; time to face reality */ 1330 error(old); 1331 name = pathlast(c->path); 1332 if(name) 1333 l = dirsetname(name, strlen(name), buf, l, sizeof buf); 1334 l = convM2D(buf, l, &d, strs); 1335 if(l == 0) 1336 error(old); 1337 packoldstat(p, &d); 1338 1339 poperror(); 1340 cclose(c); 1341 return 0; 1342 } 1343 1344 long 1345 sys_wstat(uint32 *u) 1346 { 1347 error("old wstat system call - recompile"); 1348 return -1; 1349 } 1350 1351 long 1352 sys_fwstat(uint32 *u) 1353 { 1354 error("old fwstat system call - recompile"); 1355 return -1; 1356 } 1357 1358 // Plan 9 VX additions 1359 long 1360 kbind(char *new, char *old, int flag) 1361 { 1362 return bindmount(0, -1, -1, new, old, flag, nil); 1363 } 1364 1365 long 1366 syspassfd(uint32 *u) 1367 { 1368 error("passfd unimplemented"); 1369 return -1; 1370 } 1371