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