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 wait.fid = c->fid; 601 wait.rc = rc; 602 wait.wc = nil; 603 addwaiting(sp, &wait); 604 605 h = heap(dev.Rread); 606 r = H2D(Sys_Rread *, h); 607 ptradd(h); 608 if(waserror()){ 609 ptrdel(h); 610 destroy(r); 611 delwaiting(&wait); 612 nexterror(); 613 } 614 615 crecv(rc, r); 616 delwaiting(&wait); 617 if(r->t1 != H) 618 error(string2c(r->t1)); 619 620 a = r->t0; 621 l = 0; 622 if(a != H){ 623 l = a->len; 624 if(l > count) 625 l = count; 626 memmove(va, a->data, l); 627 } 628 629 poperror(); 630 ptrdel(h); 631 destroy(r); 632 633 poperror(); 634 ptrdel(D2H(rc)); 635 destroy(rc); 636 637 poperror(); 638 release(); 639 640 return l; 641 } 642 643 static long 644 srvwrite(Chan *c, void *va, long count, vlong offset) 645 { 646 long l; 647 Heap * volatile h; 648 SrvFile *sp; 649 Channel *wc; 650 Channel *wr; 651 Pending wait; 652 Sys_Rwrite * volatile w; 653 Sys_FileIO_write req; 654 655 if(c->qid.type & QTDIR) 656 error(Eperm); 657 658 acquire(); 659 if(waserror()){ 660 release(); 661 nexterror(); 662 } 663 664 sp = c->aux; 665 wr = sp->write; 666 if(wr == H) 667 error(Ehungup); 668 669 wc = cnewc(dev.Rwrite, movtmp, 1); 670 ptradd(D2H(wc)); 671 if(waserror()){ 672 ptrdel(D2H(wc)); 673 destroy(wc); 674 nexterror(); 675 } 676 677 req.t0 = offset; 678 req.t1 = mem2array(va, count); 679 req.t2 = c->fid; 680 req.t3 = wc; 681 682 ptradd(D2H(req.t1)); 683 684 if(waserror()){ 685 ptrdel(D2H(req.t1)); 686 destroy(req.t1); 687 nexterror(); 688 } 689 690 csend(wr, &req); 691 692 poperror(); 693 ptrdel(D2H(req.t1)); 694 destroy(req.t1); 695 696 h = heap(dev.Rwrite); 697 w = H2D(Sys_Rwrite *, h); 698 ptradd(h); 699 700 wait.fid = c->fid; 701 wait.rc = nil; 702 wait.wc = wc; 703 addwaiting(sp, &wait); 704 705 if(waserror()){ 706 delwaiting(&wait); 707 ptrdel(h); 708 destroy(w); 709 nexterror(); 710 } 711 crecv(wc, w); 712 delwaiting(&wait); 713 if(w->t1 != H) 714 error(string2c(w->t1)); 715 poperror(); 716 ptrdel(h); 717 l = w->t0; 718 destroy(w); 719 720 poperror(); 721 ptrdel(D2H(wc)); 722 destroy(wc); 723 724 poperror(); 725 release(); 726 if(l < 0) 727 l = 0; 728 return l; 729 } 730 731 static void 732 srvretype(Channel *c, SrvFile *f, Type *t) 733 { 734 Heap *h; 735 736 h = D2H(c); 737 freetype(h->t); 738 h->t = t; 739 t->ref++; 740 c->aux = f; 741 } 742 743 int 744 srvf2c(char *dir, char *file, Sys_FileIO *io) 745 { 746 SrvFile *s, *f; 747 volatile struct { Chan *c; } c; 748 749 c.c = nil; 750 if(waserror()){ 751 cclose(c.c); 752 return -1; 753 } 754 755 if(strchr(file, '/') != nil || strlen(file) >= 64 || strcmp(file, ".") == 0 || strcmp(file, "..") == 0) 756 error(Efilename); 757 758 c.c = namec(dir, Aaccess, 0, 0); 759 if((c.c->qid.type&QTDIR) == 0 || devtab[c.c->type]->dc != 's') 760 error("directory not a srv device"); 761 762 s = c.c->aux; 763 764 qlock(&dev.l); 765 if(waserror()){ 766 qunlock(&dev.l); 767 nexterror(); 768 } 769 for(f = s->entry; f != nil; f = f->entry){ 770 if(strcmp(f->name, file) == 0) 771 error(Eexist); 772 } 773 774 f = malloc(sizeof(SrvFile)); 775 if(f == nil) 776 error(Enomem); 777 778 srvretype(io->read, f, Trdchan); 779 srvretype(io->write, f, Twrchan); 780 f->read = io->read; 781 f->write = io->write; 782 783 f->waitlist.next = &f->waitlist; 784 f->waitlist.prev = &f->waitlist; 785 786 kstrdup(&f->name, file); 787 kstrdup(&f->user, up->env->user); 788 f->perm = 0666 & (~0666 | (s->perm & 0666)); 789 f->length = 0; 790 f->ref = 2; 791 mkqid(&f->qid, dev.pathgen++, 0, QTFILE); 792 793 f->entry = s->entry; 794 s->entry = f; 795 s->ref++; 796 f->dir = s; 797 poperror(); 798 qunlock(&dev.l); 799 800 cclose(c.c); 801 poperror(); 802 803 return 0; 804 } 805 806 Dev srvdevtab = { 807 's', 808 "srv", 809 810 devreset, 811 srvinit, 812 devshutdown, 813 srvattach, 814 srvwalk, 815 srvstat, 816 srvopen, 817 devcreate, 818 srvclose, 819 srvread, 820 devbread, 821 srvwrite, 822 devbwrite, 823 srvremove, 824 srvwstat 825 }; 826