dev.c (11525B)
1 #include <os9/os9.h> 2 3 #include <ctype.h> 4 #include <errno.h> 5 #include <string.h> 6 7 #include <libk.h> 8 9 #include "dev.h" 10 11 /* 12 * Lock policy: 13 * The channels are locked when accessed from the raw fdset array, which is 14 * currently done by newchan() and fd2chan(). 15 * The channels are propagated through the functions in a locked state. 16 * When a channel is done being used, it needs to be unlocked. This is either 17 * done when the channel is closed by delchan(), or directly with a call to 18 * unlock() when inside of dev.c. 19 * The use of mutexes is then transparent for the drivers. 20 */ 21 22 23 int 24 sameqid(Qid q1, Qid q2) 25 { 26 return q1.type == q2.type && q1.vers == q2.vers && q1.path == q2.path; 27 } 28 29 static Chan * 30 newchan(unsigned char type) 31 { 32 Chan *c, **bp; 33 Fdset *fds = proc->fds; 34 35 lock(&fds->m); 36 for (bp = fds->fdset; bp < &fds->fdset[NR_CHANS]; ++bp) { 37 if (*bp == NULL) 38 break; 39 } 40 41 if (bp == &fds->fdset[NR_CHANS]) 42 goto err1; 43 if ((c = allocchan()) == NULL) 44 goto err2; 45 memset(c, 0, sizeof(*c)); 46 initref(&c->ref); 47 c->type = type; 48 49 lock(&c->mutex); 50 *bp = c; 51 unlock(&fds->m); 52 53 return c; 54 55 err1: 56 seterror(ENOMEM); 57 err2: 58 unlock(&fds->m); 59 return NULL; 60 } 61 62 Nspace * 63 newspace(Nspace *from) 64 { 65 int i; 66 Mpoint *mp; 67 Nspace *ns; 68 69 if ((ns = allocspace()) == NULL) 70 return NULL; 71 memset(ns, 0, sizeof(*ns)); 72 initref(&ns->ref); 73 74 if (!from) 75 return ns; 76 77 lock(&from->m); 78 for (i = 0; i <NR_MPOINTS; i++) { 79 mp = ns->mpoints[i] = from->mpoints[i]; 80 if (mp) 81 incref(&mp->ref); 82 } 83 unlock(&from->m); 84 85 return ns; 86 } 87 88 Fdset * 89 newfds(Fdset *from) 90 { 91 int i; 92 Chan *c; 93 Fdset *fds; 94 95 if ((fds = allocfds()) == NULL) 96 return NULL; 97 memset(fds, 0, sizeof(*fds)); 98 initref(&fds->ref); 99 100 if (!from) 101 return fds; 102 103 lock(&from->m); 104 for (i = 0; i < NR_CHANS; ++i) { 105 c = fds->fdset[i] = from->fdset[i]; 106 if (c) 107 incref(&c->ref); 108 } 109 unlock(&from->m); 110 111 return fds; 112 } 113 114 static void 115 delchan(Chan *c) 116 { 117 Chan **bp; 118 Fdset *fds = proc->fds; 119 120 if (!decref(&c->ref)) 121 return; 122 123 lock(&fds->m); 124 for (bp = fds->fdset; bp < &fds->fdset[NR_CHANS]; ++bp) { 125 if (*bp == c) 126 break; 127 } 128 if (bp == &fds->fdset[NR_CHANS]) 129 panic("corrupted channel"); 130 131 *bp = NULL; 132 unlock(&fds->m); 133 unlock(&c->mutex); 134 135 freechan(c); 136 } 137 138 static void 139 delmpoint(Mpoint *mp) 140 { 141 if (!decref(&mp->ref)) 142 return; 143 delchan(mp->new); 144 delchan(mp->old); 145 freempoint(mp); 146 } 147 148 void 149 delspace(Nspace *ns) 150 { 151 int i; 152 Mpoint *mp; 153 154 if (!decref(&ns->ref)) 155 return; 156 157 for (i = 0; i < NR_MPOINTS; ++i) { 158 mp = ns->mpoints[i]; 159 if (!mp) 160 continue; 161 delmpoint(mp); 162 } 163 freespace(ns); 164 } 165 166 void 167 delfds(Fdset *fds) 168 { 169 int i; 170 Chan *c; 171 172 if (!decref(&fds->ref)) 173 return; 174 175 for (i = 0; i < NR_CHANS; ++i) { 176 c = fds->fdset[i]; 177 if (!c) 178 continue; 179 lock(&c->mutex); 180 chanclose(c); 181 } 182 freefds(fds); 183 } 184 185 static Chan * 186 fd2chan(int fd) 187 { 188 Chan *c; 189 190 if (fd < 0 || fd >= NR_CHANS) 191 goto err; 192 193 c = proc->fds->fdset[fd]; 194 if (!c) 195 goto err; 196 lock(&c->mutex); 197 198 return c; 199 200 err: 201 seterror(EBADF); 202 return NULL; 203 } 204 205 static char * 206 next(char *s, char *elem) 207 { 208 int n; 209 char *t; 210 211 while (*s == '/') 212 ++s; 213 214 n = 0; 215 t = s; 216 if (*s != '\0') { 217 while (*t != '/' && *t != '\0') { 218 if (n == NAMELEN) { 219 seterror(EINVAL); 220 return NULL; 221 } 222 elem[n++] = *t++; 223 } 224 } 225 elem[n] = '\0'; 226 227 return t; 228 } 229 230 static int 231 devtype(int c) 232 { 233 int i; 234 Dev **dp; 235 236 for (i = 0, dp = devtab; *dp && (*dp)->id != c; ++dp) 237 i++; 238 if (*dp == NULL) { 239 seterror(ENODEV); 240 return -1; 241 } 242 return i; 243 } 244 245 int 246 buf2chan(Chan *c, void *dst, void *src, int nbytes, long len) 247 { 248 char *addr = src; 249 250 if (c->offset >= len) 251 return 0; 252 253 if (c->offset + nbytes > len) 254 nbytes = len - c->offset; 255 256 memcpy(dst, addr + c->offset, nbytes); 257 258 c->offset += nbytes; 259 260 return nbytes; 261 } 262 263 static Chan * 264 mntpoint(int type, Qid qid) 265 { 266 int i; 267 Chan *cn; 268 Mpoint *mp; 269 Nspace *ns = proc->ns; 270 271 lock(&ns->m); 272 for (i = 0; i < NR_MPOINTS; ++i) { 273 if ((mp = ns->mpoints[i]) == NULL) 274 continue; 275 lock(&mp->m); 276 if ((cn = mp->new) == NULL) { 277 unlock(&mp->m); 278 continue; 279 } 280 if (cn->type == type && sameqid(cn->qid, qid)) { 281 unlock(&mp->m); 282 unlock(&ns->m); 283 return mp->old; 284 } 285 unlock(&mp->m); 286 } 287 unlock(&ns->m); 288 289 return NULL; 290 } 291 292 Chan * 293 attach(int id, int dev) 294 { 295 int type; 296 297 298 if ((type = devtype(id)) < 0) 299 return NULL; 300 return devtab[type]->attach(id, dev); 301 } 302 303 Chan * 304 devattach(int id, int dev) 305 { 306 Chan *c; 307 int type; 308 309 if ((type = devtype(id)) < 0) 310 return NULL; 311 if ((c = newchan(type)) == NULL) 312 return NULL; 313 c->dev = dev; 314 c->qid = QID(CHDIR, 0, 0); 315 316 return c; 317 } 318 319 Chan * 320 namec(char *name, int mode) 321 { 322 int n, i; 323 char *s; 324 Chan *mnt, *c; 325 char el[NAMELEN]; 326 327 c = NULL; 328 switch (name[0]) { 329 case '/': 330 c = clone(&proc->slash, NULL); 331 s = name; 332 break; 333 case '#': 334 if ((s = next(name+1, el)) == NULL) 335 goto noent; 336 337 for (n = 0, i = 1; isdigit(el[i]); i++) 338 n += el[i] - '0'; 339 340 if (el[i] != '\0') 341 goto noent; 342 343 c = attach(el[0], n); 344 break; 345 default: 346 goto noent; 347 } 348 349 if (!c) 350 return NULL; 351 352 for (s = next(s, el); s && *el; s = next(s, el)) { 353 if (c->qid.type != CHDIR) 354 goto noent; 355 if (devtab[c->type]->walk(c, el) < 0) 356 goto err; 357 mnt = mntpoint(c->type, c->qid); 358 if (mnt && clone(mnt, c) < 0) 359 goto err; 360 } 361 if (!s) 362 goto err; 363 364 /* TODO: check mode */ 365 return c; 366 367 noent: 368 seterror(ENOENT); 369 err: 370 if (c) 371 delchan(c); 372 return NULL; 373 } 374 375 Chan * 376 clone(Chan *c, Chan *nc) 377 { 378 return devtab[c->type]->clone(c, nc); 379 } 380 381 Chan * 382 devclone(Chan *c, Chan *nc) 383 { 384 if (!nc && (nc = newchan(c->type)) == NULL) 385 return NULL; 386 387 nc->qid = c->qid; 388 nc->dev = c->dev; 389 nc->mode = c->mode; 390 nc->offset = c->offset; 391 nc->type = c->type; 392 393 return nc; 394 } 395 396 int 397 devwalk(Chan *c, char *name, Dirtab *tab, int ntab, Devgen *gen) 398 { 399 int i; 400 Dir dir; 401 402 if (name[0] == '.' && name[1] == '\0') 403 return 1; 404 for (i = 0; ; i++) { 405 switch ((*gen)(c, tab, ntab, i, &dir)) { 406 case 0: 407 continue; 408 case -1: 409 seterror(ENOENT); 410 return -1; 411 case 1: 412 if (strcmp(name, dir.name)) 413 continue; 414 c->qid = dir.qid; 415 return 1; 416 } 417 } 418 } 419 420 int 421 dirread(Chan *c, 422 unsigned char *buf, int nbytes, 423 Dirtab *tab, int ntab, 424 Devgen *gen) 425 { 426 int cnt, n; 427 Dir dir; 428 429 cnt = 0; 430 while (nbytes >= DIRLEN) { 431 switch ((*gen)(c, tab, ntab, c->index++, &dir)) { 432 case 0: 433 continue; 434 case -1: 435 /* FIXME: We cannot mark an error in the 1st iteration */ 436 return (cnt >= 0) ? cnt : -1; 437 case 1: 438 c->offset += DIRLEN; 439 n = dirtop9(&dir, buf + cnt, nbytes); 440 if (n < 0) { 441 seterror(EINVAL); 442 return (cnt > 0) ? cnt : -1; 443 } 444 nbytes -= n; 445 cnt += n; 446 } 447 } 448 449 return cnt; 450 } 451 452 void 453 mkentry(Chan *c, Dir *dir, 454 char *name, long length, Qid qid, unsigned mode) 455 { 456 strcpy(dir->name, name); 457 dir->length = length; 458 dir->qid = qid; 459 dir->mode = mode; 460 if (qid.type == CHDIR) 461 dir->mode |= O_DIR; 462 dir->type = c->type; 463 dir->dev = c->dev; 464 } 465 466 int 467 devgen(Chan *c, Dirtab *tab, int ntab, int n, Dir *dir) 468 { 469 Dirtab *dp; 470 471 if (!tab || n >= ntab) 472 return -1; 473 474 dp = &tab[n]; 475 mkentry(c, dir, dp->name, dp->length, dp->qid, dp->perm); 476 return 1; 477 } 478 479 int 480 chanclose(Chan *c) 481 { 482 return devtab[c->type]->close(c); 483 } 484 485 int 486 devclose(Chan *c) 487 { 488 delchan(c); 489 return 0; 490 } 491 492 int 493 close(int fd) 494 { 495 Chan *c; 496 497 if ((c = fd2chan(fd)) == NULL) 498 return -1; 499 return chanclose(c); 500 } 501 502 int 503 devstat(Chan *dirc, char *file, 504 unsigned char *buf, int n, 505 Dirtab *tab, int ntab, 506 Devgen *gen) 507 { 508 int i, r = -1; 509 Dir dir; 510 Chan *c, *mnt; 511 512 if ((c = namec(file, O_STAT)) == NULL) 513 return -1; 514 515 for (i = 0; ; i++) { 516 switch ((*gen)(dirc, tab, ntab, i, &dir)) { 517 case 0: 518 seterror(ENOENT); 519 case -1: 520 r = -1; 521 goto leave; 522 case 1: 523 mnt = mntpoint(dir.type, dir.qid); 524 if (mnt) { 525 dir.qid = mnt->qid; 526 dir.type = mnt->type; 527 } 528 if (sameqid(dir.qid, c->qid) || dir.type != c->type) 529 continue; 530 r = dirtop9(&dir, buf, n); 531 goto leave; 532 } 533 } 534 535 leave: 536 delchan(c); 537 return r; 538 } 539 540 int 541 stat(char *path, void *buf, int n) 542 { 543 int r; 544 size_t len; 545 Chan *c; 546 char *p, dirname[PATHLEN]; 547 548 if (n < DIRLEN) { 549 seterror(EINVAL); 550 return -1; 551 } 552 553 len = strlen(path); 554 if (len + 1 > sizeof(dirname)) { 555 seterror(ENAMETOOLONG); 556 return -1; 557 } 558 memcpy(dirname, path, len); 559 for (p = dirname + len; p > dirname; --p) { 560 if (*p != '/') 561 break; 562 } 563 564 p = memrchr(dirname, '/', p - dirname); 565 if (!p) { 566 seterror(ENOENT); 567 return -1; 568 } 569 dirname[p - dirname + 1] = '\0'; 570 571 if ((c = namec(dirname, O_STAT)) == NULL) 572 return -1; 573 574 r = devtab[c->type]->stat(c, path, buf, n); 575 delchan(c); 576 577 return r; 578 } 579 580 int 581 chanread(Chan *c, void *buf, int n) 582 { 583 int r = -1; 584 585 if (c->qid.type == CHDIR && n < DIRLEN) { 586 r = -1; 587 seterror(EINVAL); 588 } else { 589 r = devtab[c->type]->read(c, buf, n); 590 } 591 592 return r; 593 } 594 595 int 596 read(int fd, void *buf, int n) 597 { 598 int r; 599 Chan *c; 600 601 if ((c = fd2chan(fd)) == NULL) 602 return -1; 603 r = chanread(c, buf, n); 604 unlock(&c->mutex); 605 606 return r; 607 } 608 609 int 610 chanwrite(Chan *c, void *buf, int n) 611 { 612 int r = -1; 613 614 if (c->qid.type == CHDIR) { 615 r = -1; 616 seterror(EISDIR); 617 } else { 618 r = devtab[c->type]->write(c, buf, n); 619 } 620 621 return r; 622 } 623 624 int 625 write(int fd, void *buf, int n) 626 { 627 int r; 628 Chan *c; 629 630 if ((c = fd2chan(fd)) == NULL) 631 return -1; 632 r = chanwrite(c, buf, n); 633 unlock(&c->mutex); 634 635 return r; 636 } 637 638 int 639 seek(int fd, long off, int whence) 640 { 641 Chan *c; 642 int r = -1; 643 644 if ((c = fd2chan(fd)) == NULL) 645 return -1; 646 647 if (c->qid.type == CHDIR) 648 seterror(EISDIR); 649 else 650 r = devtab[c->type]->seek(c, off, whence); 651 652 unlock(&c->mutex); 653 return r; 654 } 655 656 int 657 fsync(int fd) 658 { 659 Chan *c; 660 int r = -1; 661 662 if ((c = fd2chan(fd)) == NULL) 663 return -1; 664 665 if (c->qid.type == CHDIR) 666 seterror(EISDIR); 667 else 668 r = devtab[c->type]->sync(c, SYNCDEV); 669 670 unlock(&c->mutex); 671 return r; 672 } 673 674 void 675 sync(void) 676 { 677 Chan *c; 678 Dev **dp; 679 680 for (dp = devtab; *dp; ++dp) { 681 c = attach((*dp)->id, 0); 682 devtab[c->type]->sync(c, SYNCALL); 683 delchan(c); 684 } 685 } 686 687 Chan * 688 deverrmount(Chan *c, char *spec) 689 { 690 seterror(EINVAL); 691 return NULL; 692 } 693 694 int 695 deverrwrite(Chan *c, void *buf, int n) 696 { 697 seterror(EINVAL); 698 return -1; 699 } 700 701 int deverrseek(Chan *c, long off, int whence) 702 { 703 seterror(EINVAL); 704 return -1; 705 } 706 707 int 708 devseek(Chan *c, long off, int whence) 709 { 710 switch (whence) { 711 case SEEK_SET: 712 c->offset = off; 713 break; 714 case SEEK_CUR: 715 c->offset += off; 716 break; 717 case SEEK_END: 718 panic("seek"); /* TODO */ 719 break; 720 } 721 722 return 0; 723 } 724 725 int 726 devsync(Chan *c, int what) 727 { 728 return 0; 729 } 730 731 static int 732 addmntpoint(Chan *c, char *new) 733 { 734 int i; 735 Chan *cn; 736 Mpoint *mp; 737 Nspace *ns = proc->ns; 738 739 if ((mp = allocmpoint()) == NULL) 740 return -1; 741 742 if ((cn = namec(new, O_READ)) == NULL) 743 goto err0; 744 745 if (cn->qid.type != CHDIR) { 746 seterror(ENOTDIR); 747 goto err1; 748 } 749 750 lock(&ns->m); 751 for (i = NR_MPOINTS-1; i >= 0 && ns->mpoints[i]; i--) 752 ; 753 if (i < 0) 754 goto err2; 755 756 ns->mpoints[i] = mp; 757 mp->new = cn; 758 mp->old = c; 759 unlock(&ns->m); 760 761 return 0; 762 763 err2: 764 seterror(ENOMEM); 765 unlock(&ns->m); 766 err1: 767 delchan(cn); 768 err0: 769 delmpoint(mp); 770 return -1; 771 } 772 773 int 774 bind(char *old, char *new) 775 { 776 Chan *c; 777 778 if ((c = namec(old, O_BIND)) == NULL) 779 return -1; 780 781 if (addmntpoint(c, new) < 0) { 782 delchan(c); 783 return -1; 784 } 785 unlock(&c->mutex); 786 787 return 0; 788 } 789 790 int 791 mount(char *srv, char *where, char *spec) 792 { 793 Chan *cs, *c; 794 795 if ((cs = namec(srv, O_RDWR)) == NULL) 796 goto err0; 797 798 c = devtab[cs->type]->mount(cs, spec); 799 delchan(cs); 800 if (!c) 801 goto err0; 802 803 if (addmntpoint(c, where) < 0) 804 goto err1; 805 806 unlock(&c->mutex); 807 return 0; 808 809 err1: 810 delchan(c); 811 err0: 812 return -1; 813 } 814 815 void 816 idev(void) 817 { 818 Chan *c; 819 820 if ((c = attach('/', 0)) == NULL) 821 panic("idev:attach"); 822 823 if (!clone(c, &proc->slash)) 824 panic("idev:clone"); 825 826 delchan(c); 827 devlink(); 828 }