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