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