1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "../port/error.h" 7 #include "interp.h" 8 #include "isa.h" 9 #include "runt.h" 10 11 typedef struct SrvFile SrvFile; 12 typedef struct Pending Pending; 13 14 /* request pending to a server, in case a server vanishes */ 15 struct Pending 16 { 17 Pending* next; 18 Pending* prev; 19 int fid; 20 Channel* rc; 21 Channel* wc; 22 }; 23 24 struct SrvFile 25 { 26 char* name; 27 char* user; 28 ulong perm; 29 Qid qid; 30 int ref; 31 32 /* root directory */ 33 char* spec; 34 SrvFile* devlist; 35 SrvFile* entry; 36 37 /* file */ 38 int opens; 39 int flags; 40 vlong length; 41 Channel* read; 42 Channel* write; 43 SrvFile* dir; /* parent directory */ 44 Pending waitlist; /* pending requests from client opens */ 45 }; 46 47 enum 48 { 49 SORCLOSE = (1<<0), 50 SRDCLOSE = (1<<1), 51 SWRCLOSE = (1<<2), 52 SREMOVED = (1<<3), 53 }; 54 55 typedef struct SrvDev SrvDev; 56 struct SrvDev 57 { 58 Type* Rread; 59 Type* Rwrite; 60 QLock l; 61 ulong pathgen; 62 SrvFile* devices; 63 }; 64 65 static SrvDev dev; 66 67 void freechan(Heap*, int); 68 static void freerdchan(Heap*, int); 69 static void freewrchan(Heap*, int); 70 static void delwaiting(Pending*); 71 72 Type *Trdchan; 73 Type *Twrchan; 74 75 static int 76 srvgen(Chan *c, char *name, Dirtab *tab, int ntab, int s, Dir *dp) 77 { 78 SrvFile *f; 79 80 USED(name); 81 USED(tab); 82 USED(ntab); 83 84 if(s == DEVDOTDOT){ 85 devdir(c, c->qid, "#s", 0, eve, 0555, dp); 86 return 1; 87 } 88 f = c->aux; 89 if((c->qid.type & QTDIR) == 0){ 90 if(s > 0) 91 return -1; 92 devdir(c, f->qid, f->name, f->length, f->user, f->perm, dp); 93 return 1; 94 } 95 96 for(f = f->entry; f != nil; f = f->entry){ 97 if(s-- == 0) 98 break; 99 } 100 if(f == nil) 101 return -1; 102 103 devdir(c, f->qid, f->name, f->length, f->user, f->perm, dp); 104 return 1; 105 } 106 107 static void 108 srvinit(void) 109 { 110 static uchar rmap[] = Sys_Rread_map; 111 static uchar wmap[] = Sys_Rwrite_map; 112 113 Trdchan = dtype(freerdchan, sizeof(Channel), Tchannel.map, Tchannel.np); 114 Twrchan = dtype(freewrchan, sizeof(Channel), Tchannel.map, Tchannel.np); 115 116 dev.pathgen = 1; 117 dev.Rread = dtype(freeheap, Sys_Rread_size, rmap, sizeof(rmap)); 118 dev.Rwrite = dtype(freeheap, Sys_Rwrite_size, wmap, sizeof(wmap)); 119 } 120 121 static int 122 srvcanattach(SrvFile *d) 123 { 124 if(strcmp(d->user, up->env->user) == 0) 125 return 1; 126 127 /* 128 * Need write permission in other to allow attaches if 129 * we are not the owner 130 */ 131 if(d->perm & 2) 132 return 1; 133 134 return 0; 135 } 136 137 static Chan* 138 srvattach(char *spec) 139 { 140 Chan *c; 141 SrvFile *d; 142 char srvname[16]; 143 144 qlock(&dev.l); 145 if(waserror()){ 146 qunlock(&dev.l); 147 nexterror(); 148 } 149 150 if(spec[0] != '\0'){ 151 for(d = dev.devices; d != nil; d = d->devlist){ 152 if(strcmp(spec, d->spec) == 0){ 153 if(!srvcanattach(d)) 154 error(Eperm); 155 c = devattach('s', spec); 156 c->aux = d; 157 c->qid = d->qid; 158 d->ref++; 159 poperror(); 160 qunlock(&dev.l); 161 return c; 162 } 163 } 164 } 165 166 d = malloc(sizeof(SrvFile)); 167 if(d == nil) 168 error(Enomem); 169 170 d->ref = 1; 171 kstrdup(&d->spec, spec); 172 kstrdup(&d->user, up->env->user); 173 snprint(srvname, sizeof(srvname), "srv%ld", up->env->pgrp->pgrpid); 174 kstrdup(&d->name, srvname); 175 d->perm = DMDIR|0770; 176 mkqid(&d->qid, dev.pathgen++, 0, QTDIR); 177 178 d->devlist = dev.devices; 179 dev.devices = d; 180 181 poperror(); 182 qunlock(&dev.l); 183 184 c = devattach('s', spec); 185 c->aux = d; 186 c->qid = d->qid; 187 188 return c; 189 } 190 191 static Walkqid* 192 srvwalk(Chan *c, Chan *nc, char **name, int nname) 193 { 194 SrvFile *d, *pd; 195 Walkqid *w; 196 197 pd = c->aux; 198 qlock(&dev.l); 199 if(waserror()){ 200 qunlock(&dev.l); 201 nexterror(); 202 } 203 204 w = devwalk(c, nc, name, nname, nil, 0, srvgen); 205 if(w != nil && w->clone != nil){ 206 if(nname != 0){ 207 for(d = pd->entry; d != nil; d = d->entry) 208 if(d->qid.path == w->clone->qid.path) 209 break; 210 if(d == nil) 211 panic("srvwalk"); 212 if(w->clone == c) 213 pd->ref--; 214 }else 215 d = pd; 216 w->clone->aux = d; 217 d->ref++; 218 } 219 220 poperror(); 221 qunlock(&dev.l); 222 return w; 223 } 224 225 static int 226 srvstat(Chan *c, uchar *db, int n) 227 { 228 qlock(&dev.l); 229 if(waserror()){ 230 qunlock(&dev.l); 231 nexterror(); 232 } 233 n = devstat(c, db, n, 0, 0, srvgen); 234 poperror(); 235 qunlock(&dev.l); 236 return n; 237 } 238 239 static Chan* 240 srvopen(Chan *c, int omode) 241 { 242 SrvFile *sf; 243 244 openmode(omode); /* check it */ 245 if(c->qid.type & QTDIR){ 246 if(omode != OREAD) 247 error(Eisdir); 248 c->mode = omode; 249 c->flag |= COPEN; 250 c->offset = 0; 251 return c; 252 } 253 254 sf = c->aux; 255 256 qlock(&dev.l); 257 if(waserror()){ 258 qunlock(&dev.l); 259 nexterror(); 260 } 261 devpermcheck(sf->user, sf->perm, omode); 262 if(omode&ORCLOSE && strcmp(sf->user, up->env->user) != 0) 263 error(Eperm); 264 if(sf->perm & DMEXCL && sf->opens != 0) 265 error(Einuse); 266 sf->opens++; 267 if(omode&ORCLOSE) 268 sf->flags |= SORCLOSE; 269 poperror(); 270 qunlock(&dev.l); 271 272 c->offset = 0; 273 c->flag |= COPEN; 274 c->mode = openmode(omode); 275 276 return c; 277 } 278 279 static int 280 srvwstat(Chan *c, uchar *dp, int n) 281 { 282 Dir *d; 283 SrvFile *sf, *f; 284 285 sf = c->aux; 286 if(strcmp(up->env->user, sf->user) != 0) 287 error(Eperm); 288 289 d = smalloc(sizeof(*d)+n); 290 if(waserror()){ 291 free(d); 292 nexterror(); 293 } 294 n = convM2D(dp, n, d, (char*)&d[1]); 295 if(n == 0) 296 error(Eshortstat); 297 if(!emptystr(d->name)){ 298 if(sf->dir == nil) 299 error(Eperm); 300 validwstatname(d->name); 301 qlock(&dev.l); 302 for(f = sf->dir; f != nil; f = f->entry) 303 if(strcmp(f->name, d->name) == 0){ 304 qunlock(&dev.l); 305 error(Eexist); 306 } 307 kstrdup(&sf->name, d->name); 308 qunlock(&dev.l); 309 } 310 if(d->mode != ~0UL) 311 sf->perm = d->mode & (DMEXCL|DMAPPEND|0777); 312 if(d->length != (vlong)-1) 313 sf->length = d->length; 314 poperror(); 315 free(d); 316 return n; 317 } 318 319 static void 320 srvputdir(SrvFile *dir) 321 { 322 SrvFile **l, *d; 323 324 dir->ref--; 325 if(dir->ref != 0) 326 return; 327 328 for(l = &dev.devices; (d = *l) != nil; l = &d->devlist) 329 if(d == dir){ 330 *l = d->devlist; 331 break; 332 } 333 free(dir->spec); 334 free(dir->user); 335 free(dir->name); 336 free(dir); 337 } 338 339 static void 340 srvunblock(SrvFile *sf, int fid) 341 { 342 Channel *d; 343 Sys_FileIO_read rreq; 344 Sys_FileIO_write wreq; 345 346 acquire(); 347 if(waserror()){ 348 release(); 349 nexterror(); 350 } 351 d = sf->read; 352 if(d != H){ 353 rreq.t0 = 0; 354 rreq.t1 = 0; 355 rreq.t2 = fid; 356 rreq.t3 = H; 357 csendalt(d, &rreq, d->mid.t, -1); 358 } 359 360 d = sf->write; 361 if(d != H){ 362 wreq.t0 = 0; 363 wreq.t1 = H; 364 wreq.t2 = fid; 365 wreq.t3 = H; 366 csendalt(d, &wreq, d->mid.t, -1); 367 } 368 poperror(); 369 release(); 370 } 371 372 static void 373 srvcancelreqs(SrvFile *sf) 374 { 375 Pending *w, *ws; 376 Sys_Rread rreply; 377 Sys_Rwrite wreply; 378 379 acquire(); 380 ws = &sf->waitlist; 381 while((w = ws->next) != ws){ 382 delwaiting(w); 383 if(waserror() == 0){ 384 if(w->rc != nil){ 385 rreply.t0 = H; 386 rreply.t1 = c2string(Ehungup, strlen(Ehungup)); 387 csend(w->rc, &rreply); 388 } 389 if(w->wc != nil){ 390 wreply.t0 = 0; 391 wreply.t1 = c2string(Ehungup, strlen(Ehungup)); 392 csend(w->wc, &wreply); 393 } 394 poperror(); 395 } 396 } 397 release(); 398 } 399 400 static void 401 srvdelete(SrvFile *sf) 402 { 403 SrvFile *f, **l; 404 405 if((sf->flags & SREMOVED) == 0){ 406 for(l = &sf->dir->entry; (f = *l) != nil; l = &f->entry){ 407 if(sf == f){ 408 *l = f->entry; 409 break; 410 } 411 } 412 sf->ref--; 413 sf->flags |= SREMOVED; 414 } 415 } 416 417 static void 418 srvchkref(SrvFile *sf) 419 { 420 if(sf->ref != 0) 421 return; 422 423 if(sf->dir != nil) 424 srvputdir(sf->dir); 425 426 free(sf->user); 427 free(sf->name); 428 free(sf); 429 } 430 431 static void 432 srvfree(SrvFile *sf, int flag) 433 { 434 sf->flags |= flag; 435 if((sf->flags & (SRDCLOSE | SWRCLOSE)) == (SRDCLOSE | SWRCLOSE)){ 436 sf->ref--; 437 srvdelete(sf); 438 /* no further requests can arrive; return error to pending requests */ 439 srvcancelreqs(sf); 440 srvchkref(sf); 441 } 442 } 443 444 static void 445 freerdchan(Heap *h, int swept) 446 { 447 SrvFile *sf; 448 449 release(); 450 qlock(&dev.l); 451 sf = H2D(Channel*, h)->aux; 452 sf->read = H; 453 srvfree(sf, SRDCLOSE); 454 qunlock(&dev.l); 455 acquire(); 456 457 freechan(h, swept); 458 } 459 460 static void 461 freewrchan(Heap *h, int swept) 462 { 463 SrvFile *sf; 464 465 release(); 466 qlock(&dev.l); 467 sf = H2D(Channel*, h)->aux; 468 sf->write = H; 469 srvfree(sf, SWRCLOSE); 470 qunlock(&dev.l); 471 acquire(); 472 473 freechan(h, swept); 474 } 475 476 static void 477 srvclunk(Chan *c, int remove) 478 { 479 int opens, noperm; 480 SrvFile *sf; 481 482 sf = c->aux; 483 qlock(&dev.l); 484 if(c->qid.type & QTDIR){ 485 srvputdir(sf); 486 qunlock(&dev.l); 487 if(remove) 488 error(Eperm); 489 return; 490 } 491 opens = 0; 492 if(c->flag & COPEN){ 493 opens = sf->opens--; 494 if(sf->read != H || sf->write != H) 495 srvunblock(sf, c->fid); 496 } 497 498 sf->ref--; 499 if(opens == 1){ 500 if(sf->flags & SORCLOSE) 501 remove = 1; 502 } 503 504 noperm = 0; 505 if(remove && strcmp(sf->dir->user, up->env->user) != 0){ 506 noperm = 1; 507 remove = 0; 508 } 509 if(remove) 510 srvdelete(sf); 511 srvchkref(sf); 512 qunlock(&dev.l); 513 514 if(noperm) 515 error(Eperm); 516 } 517 518 static void 519 srvclose(Chan *c) 520 { 521 srvclunk(c, 0); 522 } 523 524 static void 525 srvremove(Chan *c) 526 { 527 srvclunk(c, 1); 528 } 529 530 static void 531 addwaiting(SrvFile *sp, Pending *w) 532 { 533 Pending *sw; 534 535 sw = &sp->waitlist; 536 w->next = sw; 537 w->prev = sw->prev; 538 sw->prev->next = w; 539 sw->prev = w; 540 } 541 542 static void 543 delwaiting(Pending *w) 544 { 545 w->next->prev = w->prev; 546 w->prev->next = w->next; 547 } 548 549 static long 550 srvread(Chan *c, void *va, long count, vlong offset) 551 { 552 int l; 553 Heap * volatile h; 554 Array *a; 555 SrvFile *sp; 556 Channel *rc; 557 Channel *rd; 558 Pending wait; 559 Sys_Rread * volatile r; 560 Sys_FileIO_read req; 561 562 if(c->qid.type & QTDIR){ 563 qlock(&dev.l); 564 if(waserror()){ 565 qunlock(&dev.l); 566 nexterror(); 567 } 568 l = devdirread(c, va, count, 0, 0, srvgen); 569 poperror(); 570 qunlock(&dev.l); 571 return l; 572 } 573 574 sp = c->aux; 575 576 acquire(); 577 if(waserror()){ 578 release(); 579 nexterror(); 580 } 581 582 rd = sp->read; 583 if(rd == H) 584 error(Ehungup); 585 586 rc = cnewc(dev.Rread, movtmp, 1); 587 ptradd(D2H(rc)); 588 if(waserror()){ 589 ptrdel(D2H(rc)); 590 destroy(rc); 591 nexterror(); 592 } 593 594 req.t0 = offset; 595 req.t1 = count; 596 req.t2 = c->fid; 597 req.t3 = rc; 598 csend(rd, &req); 599 600 h = heap(dev.Rread); 601 r = H2D(Sys_Rread *, h); 602 ptradd(h); 603 if(waserror()){ 604 ptrdel(h); 605 destroy(r); 606 nexterror(); 607 } 608 609 wait.fid = c->fid; 610 wait.rc = rc; 611 wait.wc = nil; 612 addwaiting(sp, &wait); 613 if(waserror()){ 614 delwaiting(&wait); 615 nexterror(); 616 } 617 crecv(rc, r); 618 poperror(); 619 delwaiting(&wait); 620 621 if(r->t1 != H) 622 error(string2c(r->t1)); 623 624 a = r->t0; 625 l = 0; 626 if(a != H){ 627 l = a->len; 628 if(l > count) 629 l = count; 630 memmove(va, a->data, l); 631 } 632 633 poperror(); 634 ptrdel(h); 635 destroy(r); 636 637 poperror(); 638 ptrdel(D2H(rc)); 639 destroy(rc); 640 641 poperror(); 642 release(); 643 644 return l; 645 } 646 647 static long 648 srvwrite(Chan *c, void *va, long count, vlong offset) 649 { 650 long l; 651 Heap * volatile h; 652 SrvFile *sp; 653 Channel *wc; 654 Channel *wr; 655 Pending wait; 656 Sys_Rwrite * volatile w; 657 Sys_FileIO_write req; 658 659 if(c->qid.type & QTDIR) 660 error(Eperm); 661 662 acquire(); 663 if(waserror()){ 664 release(); 665 nexterror(); 666 } 667 668 sp = c->aux; 669 wr = sp->write; 670 if(wr == H) 671 error(Ehungup); 672 673 wc = cnewc(dev.Rwrite, movtmp, 1); 674 ptradd(D2H(wc)); 675 if(waserror()){ 676 ptrdel(D2H(wc)); 677 destroy(wc); 678 nexterror(); 679 } 680 681 req.t0 = offset; 682 req.t1 = mem2array(va, count); 683 req.t2 = c->fid; 684 req.t3 = wc; 685 686 ptradd(D2H(req.t1)); 687 688 if(waserror()){ 689 ptrdel(D2H(req.t1)); 690 destroy(req.t1); 691 nexterror(); 692 } 693 694 csend(wr, &req); 695 696 poperror(); 697 ptrdel(D2H(req.t1)); 698 destroy(req.t1); 699 700 h = heap(dev.Rwrite); 701 w = H2D(Sys_Rwrite *, h); 702 ptradd(h); 703 704 if(waserror()){ 705 ptrdel(h); 706 destroy(w); 707 nexterror(); 708 } 709 710 wait.fid = c->fid; 711 wait.rc = nil; 712 wait.wc = wc; 713 addwaiting(sp, &wait); 714 if(waserror()){ 715 delwaiting(&wait); 716 nexterror(); 717 } 718 crecv(wc, w); 719 poperror(); 720 delwaiting(&wait); 721 722 if(w->t1 != H) 723 error(string2c(w->t1)); 724 poperror(); 725 ptrdel(h); 726 l = w->t0; 727 destroy(w); 728 729 poperror(); 730 ptrdel(D2H(wc)); 731 destroy(wc); 732 733 poperror(); 734 release(); 735 if(l < 0) 736 l = 0; 737 return l; 738 } 739 740 static void 741 srvretype(Channel *c, SrvFile *f, Type *t) 742 { 743 Heap *h; 744 745 h = D2H(c); 746 freetype(h->t); 747 h->t = t; 748 t->ref++; 749 c->aux = f; 750 } 751 752 int 753 srvf2c(char *dir, char *file, Sys_FileIO *io) 754 { 755 SrvFile *s, *f; 756 volatile struct { Chan *c; } c; 757 758 c.c = nil; 759 if(waserror()){ 760 cclose(c.c); 761 return -1; 762 } 763 764 if(strchr(file, '/') != nil || strlen(file) >= 64 || strcmp(file, ".") == 0 || strcmp(file, "..") == 0) 765 error(Efilename); 766 767 c.c = namec(dir, Aaccess, 0, 0); 768 if((c.c->qid.type&QTDIR) == 0 || devtab[c.c->type]->dc != 's') 769 error("directory not a srv device"); 770 771 s = c.c->aux; 772 773 qlock(&dev.l); 774 if(waserror()){ 775 qunlock(&dev.l); 776 nexterror(); 777 } 778 for(f = s->entry; f != nil; f = f->entry){ 779 if(strcmp(f->name, file) == 0) 780 error(Eexist); 781 } 782 783 f = malloc(sizeof(SrvFile)); 784 if(f == nil) 785 error(Enomem); 786 787 srvretype(io->read, f, Trdchan); 788 srvretype(io->write, f, Twrchan); 789 f->read = io->read; 790 f->write = io->write; 791 792 f->waitlist.next = &f->waitlist; 793 f->waitlist.prev = &f->waitlist; 794 795 kstrdup(&f->name, file); 796 kstrdup(&f->user, up->env->user); 797 f->perm = 0666 & (~0666 | (s->perm & 0666)); 798 f->length = 0; 799 f->ref = 2; 800 mkqid(&f->qid, dev.pathgen++, 0, QTFILE); 801 802 f->entry = s->entry; 803 s->entry = f; 804 s->ref++; 805 f->dir = s; 806 poperror(); 807 qunlock(&dev.l); 808 809 cclose(c.c); 810 poperror(); 811 812 return 0; 813 } 814 815 Dev srvdevtab = { 816 's', 817 "srv", 818 819 devreset, 820 srvinit, 821 devshutdown, 822 srvattach, 823 srvwalk, 824 srvstat, 825 srvopen, 826 devcreate, 827 srvclose, 828 srvread, 829 devbread, 830 srvwrite, 831 devbwrite, 832 srvremove, 833 srvwstat 834 }; 835