1 #include <u.h> 2 #include <libc.h> 3 #include <auth.h> 4 #include <fcall.h> 5 #include <bio.h> 6 #include <ndb.h> 7 #include <thread.h> 8 9 /* 10 * This fs presents a 1 level file system. It contains 11 * three files per console (xxx and xxxctl and xxxstat) 12 */ 13 14 typedef struct Console Console; 15 typedef struct Fid Fid; 16 typedef struct Request Request; 17 typedef struct Reqlist Reqlist; 18 typedef struct Fs Fs; 19 20 enum 21 { 22 /* last 5 bits of qid.path */ 23 Textern= 0, /* fake parent of top level */ 24 Ttopdir, /* top level directory */ 25 Qctl, 26 Qstat, 27 Qdata, 28 29 Bufsize= 32*1024, /* chars buffered per reader */ 30 Maxcons= 64, /* maximum consoles */ 31 Nhash= 64, /* Fid hash buckets */ 32 }; 33 34 #define TYPE(x) (((ulong)x.path) & 0xf) 35 #define CONS(x) ((((ulong)x.path) >> 4)&0xfff) 36 #define QID(c, x) (((c)<<4) | (x)) 37 38 struct Request 39 { 40 Request *next; 41 Fid *fid; 42 Fs *fs; 43 Fcall f; 44 uchar buf[1]; 45 }; 46 47 struct Reqlist 48 { 49 Lock; 50 Request *first; 51 Request *last; 52 }; 53 54 struct Fid 55 { 56 Lock; 57 Fid *next; /* hash list */ 58 Fid *cnext; /* list of Fid's on a console */ 59 int fid; 60 int ref; 61 62 int attached; 63 int open; 64 char *user; 65 Qid qid; 66 67 Console *c; 68 69 char buf[Bufsize]; 70 char *rp; 71 char *wp; 72 73 Reqlist r; /* active read requests */ 74 }; 75 76 struct Console 77 { 78 Lock; 79 80 char *name; 81 char *dev; 82 int speed; 83 int cronly; 84 int ondemand; /* open only on demand */ 85 86 int pid; /* pid of reader */ 87 88 int fd; 89 int cfd; 90 int sfd; 91 92 Fid *flist; /* open fids to broadcast to */ 93 }; 94 95 struct Fs 96 { 97 Lock; 98 99 int fd; /* to kernel mount point */ 100 int messagesize; 101 Fid *hash[Nhash]; 102 Console *cons[Maxcons]; 103 int ncons; 104 }; 105 106 extern void console(Fs*, char*, char*, int, int, int); 107 extern Fs* fsmount(char*); 108 109 extern void fsreader(void*); 110 extern void fsrun(void*); 111 extern Fid* fsgetfid(Fs*, int); 112 extern void fsputfid(Fs*, Fid*); 113 extern int fsdirgen(Fs*, Qid, int, Dir*, uchar*, int); 114 extern void fsreply(Fs*, Request*, char*); 115 extern void fskick(Fs*, Fid*); 116 extern int fsreopen(Fs*, Console*); 117 118 extern void fsversion(Fs*, Request*, Fid*); 119 extern void fsflush(Fs*, Request*, Fid*); 120 extern void fsauth(Fs*, Request*, Fid*); 121 extern void fsattach(Fs*, Request*, Fid*); 122 extern void fswalk(Fs*, Request*, Fid*); 123 extern void fsclwalk(Fs*, Request*, Fid*); 124 extern void fsopen(Fs*, Request*, Fid*); 125 extern void fscreate(Fs*, Request*, Fid*); 126 extern void fsread(Fs*, Request*, Fid*); 127 extern void fswrite(Fs*, Request*, Fid*); 128 extern void fsclunk(Fs*, Request*, Fid*); 129 extern void fsremove(Fs*, Request*, Fid*); 130 extern void fsstat(Fs*, Request*, Fid*); 131 extern void fswstat(Fs*, Request*, Fid*); 132 133 134 void (*fcall[])(Fs*, Request*, Fid*) = 135 { 136 [Tflush] fsflush, 137 [Tversion] fsversion, 138 [Tauth] fsauth, 139 [Tattach] fsattach, 140 [Twalk] fswalk, 141 [Topen] fsopen, 142 [Tcreate] fscreate, 143 [Tread] fsread, 144 [Twrite] fswrite, 145 [Tclunk] fsclunk, 146 [Tremove] fsremove, 147 [Tstat] fsstat, 148 [Twstat] fswstat 149 }; 150 151 char Eperm[] = "permission denied"; 152 char Eexist[] = "file does not exist"; 153 char Enotdir[] = "not a directory"; 154 char Eisopen[] = "file already open"; 155 char Ebadcount[] = "bad read/write count"; 156 char Enofid[] = "no such fid"; 157 158 char *consoledb = "/lib/ndb/consoledb"; 159 char *mntpt = "/mnt/consoles"; 160 161 int messagesize = 8192+IOHDRSZ; 162 163 void 164 fatal(char *fmt, ...) 165 { 166 va_list arg; 167 char buf[1024]; 168 169 write(2, "consolefs: ", 10); 170 va_start(arg, fmt); 171 vseprint(buf, buf+1024, fmt, arg); 172 va_end(arg); 173 write(2, buf, strlen(buf)); 174 write(2, "\n", 1); 175 threadexitsall(fmt); 176 } 177 178 179 void* 180 emalloc(uint n) 181 { 182 void *p; 183 184 p = malloc(n); 185 if(p == nil) 186 fatal("malloc failed: %r"); 187 memset(p, 0, n); 188 return p; 189 } 190 191 int debug; 192 Ndb *db; 193 194 /* 195 * any request that can get queued for a delayed reply 196 */ 197 Request* 198 allocreq(Fs *fs, int bufsize) 199 { 200 Request *r; 201 202 r = emalloc(sizeof(Request)+bufsize); 203 r->fs = fs; 204 r->next = nil; 205 return r; 206 } 207 208 /* 209 * for maintaining lists of requests 210 */ 211 void 212 addreq(Reqlist *l, Request *r) 213 { 214 lock(l); 215 if(l->first == nil) 216 l->first = r; 217 else 218 l->last->next = r; 219 l->last = r; 220 r->next = nil; 221 unlock(l); 222 } 223 224 /* 225 * remove the first request from a list of requests 226 */ 227 Request* 228 remreq(Reqlist *l) 229 { 230 Request *r; 231 232 lock(l); 233 r = l->first; 234 if(r != nil) 235 l->first = r->next; 236 unlock(l); 237 return r; 238 } 239 240 /* 241 * remove a request with the given tag from a list of requests 242 */ 243 Request* 244 remtag(Reqlist *l, int tag) 245 { 246 Request *or, **ll; 247 248 lock(l); 249 ll = &l->first; 250 for(or = *ll; or; or = or->next){ 251 if(or->f.tag == tag){ 252 *ll = or->next; 253 unlock(l); 254 return or; 255 } 256 ll = &or->next; 257 } 258 unlock(l); 259 return nil; 260 } 261 262 Qid 263 parentqid(Qid q) 264 { 265 if(q.type & QTDIR) 266 return (Qid){QID(0, Textern), 0, QTDIR}; 267 else 268 return (Qid){QID(0, Ttopdir), 0, QTDIR}; 269 } 270 271 int 272 fsdirgen(Fs *fs, Qid parent, int i, Dir *d, uchar *buf, int nbuf) 273 { 274 static char name[64]; 275 char *p; 276 int xcons; 277 278 d->uid = d->gid = d->muid = "network"; 279 d->length = 0; 280 d->atime = time(nil); 281 d->mtime = d->atime; 282 d->type = 'C'; 283 d->dev = '0'; 284 285 switch(TYPE(parent)){ 286 case Textern: 287 if(i != 0) 288 return -1; 289 p = "consoles"; 290 d->mode = DMDIR|0555; 291 d->qid.type = QTDIR; 292 d->qid.path = QID(0, Ttopdir); 293 d->qid.vers = 0; 294 break; 295 case Ttopdir: 296 xcons = i/3; 297 if(xcons >= fs->ncons) 298 return -1; 299 p = fs->cons[xcons]->name; 300 switch(i%3){ 301 case 0: 302 if(fs->cons[xcons]->cfd < 0) 303 return 0; 304 snprint(name, sizeof name, "%sctl", p); 305 p = name; 306 d->qid.type = QTFILE; 307 d->qid.path = QID(xcons, Qctl); 308 d->qid.vers = 0; 309 break; 310 case 1: 311 if(fs->cons[xcons]->sfd < 0) 312 return 0; 313 snprint(name, sizeof name, "%sstat", p); 314 p = name; 315 d->qid.type = QTFILE; 316 d->qid.path = QID(xcons, Qstat); 317 d->qid.vers = 0; 318 break; 319 case 2: 320 d->qid.type = QTFILE; 321 d->qid.path = QID(xcons, Qdata); 322 d->qid.vers = 0; 323 break; 324 } 325 d->mode = 0666; 326 break; 327 default: 328 return -1; 329 } 330 d->name = p; 331 if(buf != nil) 332 return convD2M(d, buf, nbuf); 333 return 1; 334 } 335 336 /* 337 * mount the user interface and start a request processor 338 */ 339 Fs* 340 fsmount(char *mntpt) 341 { 342 Fs *fs; 343 int pfd[2], srv; 344 char buf[32]; 345 int n; 346 static void *v[2]; 347 348 fs = emalloc(sizeof(Fs)); 349 350 if(pipe(pfd) < 0) 351 fatal("opening pipe: %r"); 352 353 /* start up the file system process */ 354 v[0] = fs; 355 v[1] = pfd; 356 proccreate(fsrun, v, 16*1024); 357 358 /* Typically mounted before /srv exists */ 359 if(access("#s/consoles", AEXIST) < 0){ 360 srv = create("#s/consoles", OWRITE, 0666); 361 if(srv < 0) 362 fatal("post: %r"); 363 364 n = sprint(buf, "%d", pfd[1]); 365 if(write(srv, buf, n) < 0) 366 fatal("write srv: %r"); 367 368 close(srv); 369 } 370 371 mount(pfd[1], -1, mntpt, MBEFORE, ""); 372 close(pfd[1]); 373 return fs; 374 } 375 376 /* 377 * reopen a console 378 */ 379 int 380 fsreopen(Fs* fs, Console *c) 381 { 382 char buf[128]; 383 static void *v[2]; 384 385 if(c->pid){ 386 if(postnote(PNPROC, c->pid, "reopen") != 0) 387 fprint(2, "postnote failed: %r\n"); 388 c->pid = 0; 389 } 390 391 if(c->fd >= 0){ 392 close(c->fd); 393 close(c->cfd); 394 close(c->sfd); 395 c->cfd = -1; 396 c->fd = -1; 397 c->sfd = -1; 398 } 399 400 if(c->flist == nil && c->ondemand) 401 return 0; 402 403 c->fd = open(c->dev, ORDWR); 404 if(c->fd < 0) 405 return -1; 406 407 snprint(buf, sizeof(buf), "%sctl", c->dev); 408 c->cfd = open(buf, ORDWR); 409 fprint(c->cfd, "b%d", c->speed); 410 411 snprint(buf, sizeof(buf), "%sstat", c->dev); 412 c->sfd = open(buf, OREAD); 413 414 v[0] = fs; 415 v[1] = c; 416 proccreate(fsreader, v, 16*1024); 417 418 return 0; 419 } 420 421 void 422 change(Fs *fs, Console *c, int doreopen, int speed, int cronly, int ondemand) 423 { 424 lock(c); 425 426 if(speed != c->speed){ 427 c->speed = speed; 428 doreopen = 1; 429 } 430 if(ondemand != c->ondemand){ 431 c->ondemand = ondemand; 432 doreopen = 1; 433 } 434 c->cronly = cronly; 435 if(doreopen) 436 fsreopen(fs, c); 437 438 unlock(c); 439 } 440 441 /* 442 * create a console interface 443 */ 444 void 445 console(Fs* fs, char *name, char *dev, int speed, int cronly, int ondemand) 446 { 447 Console *c; 448 char *x; 449 int i, doreopen; 450 451 if(fs->ncons >= Maxcons) 452 fatal("too many consoles, too little time"); 453 454 doreopen = 0; 455 for(i = 0; i < fs->ncons; i++){ 456 c = fs->cons[i]; 457 if(strcmp(name, c->name) == 0){ 458 if(strcmp(dev, c->dev) != 0){ 459 /* new device */ 460 x = c->dev; 461 c->dev = strdup(dev); 462 free(x); 463 doreopen = 1; 464 } 465 change(fs, c, doreopen, speed, cronly, ondemand); 466 return; 467 } 468 } 469 for(i = 0; i < fs->ncons; i++){ 470 c = fs->cons[i]; 471 if(strcmp(dev, c->dev) == 0){ 472 /* at least a rename */ 473 x = c->name; 474 c->name = strdup(name); 475 free(x); 476 change(fs, c, doreopen, speed, cronly, ondemand); 477 return; 478 } 479 } 480 481 c = emalloc(sizeof(Console)); 482 fs->cons[fs->ncons++] = c; 483 c->name = strdup(name); 484 c->dev = strdup(dev); 485 c->fd = -1; 486 c->cfd = -1; 487 c->sfd = -1; 488 change(fs, c, 1, speed, cronly, ondemand); 489 } 490 491 /* 492 * buffer data from console to a client. 493 * circular q with writer able to catch up to reader. 494 * the reader may miss data but always sees an in order sequence. 495 */ 496 void 497 fromconsole(Fid *f, char *p, int n) 498 { 499 char *rp, *wp, *ep; 500 int pass; 501 502 lock(f); 503 rp = f->rp; 504 wp = f->wp; 505 ep = f->buf + sizeof(f->buf); 506 pass = 0; 507 while(n--){ 508 *wp++ = *p++; 509 if(wp >= ep) 510 wp = f->buf; 511 if(rp == wp) 512 pass = 1; 513 } 514 f->wp = wp; 515 516 /* we overtook the read pointer, push it up so readers always 517 * see the tail of what was written 518 */ 519 if(pass){ 520 wp++; 521 if(wp >= ep) 522 f->rp = f->buf; 523 else 524 f->rp = wp; 525 } 526 unlock(f); 527 } 528 529 /* 530 * broadcast a list of members to all listeners 531 */ 532 void 533 bcastmembers(Fs *fs, Console *c, char *msg, Fid *f) 534 { 535 int n; 536 Fid *fl; 537 char buf[512]; 538 539 sprint(buf, "[%s%s", msg, f->user); 540 for(fl = c->flist; fl != nil && strlen(buf) + 64 < sizeof(buf); fl = fl->cnext){ 541 if(f == fl) 542 continue; 543 strcat(buf, ", "); 544 strcat(buf, fl->user); 545 } 546 strcat(buf, "]\n"); 547 548 n = strlen(buf); 549 for(fl = c->flist; fl; fl = fl->cnext){ 550 fromconsole(fl, buf, n); 551 fskick(fs, fl); 552 } 553 } 554 555 void 556 handler(void*, char *msg) 557 { 558 if(strstr(msg, "reopen")) 559 noted(NCONT); 560 noted(NDFLT); 561 } 562 563 564 /* 565 * a process to read console output and broadcast it (one per console) 566 */ 567 void 568 fsreader(void *v) 569 { 570 int n; 571 Fid *fl; 572 char buf[1024]; 573 Fs *fs; 574 Console *c; 575 void **a; 576 577 a = v; 578 fs = a[0]; 579 c = a[1]; 580 c->pid = getpid(); 581 notify(handler); 582 for(;;){ 583 n = read(c->fd, buf, sizeof(buf)); 584 if(n < 0) 585 break; 586 lock(c); 587 for(fl = c->flist; fl; fl = fl->cnext){ 588 fromconsole(fl, buf, n); 589 fskick(fs, fl); 590 } 591 unlock(c); 592 } 593 } 594 595 void 596 readdb(Fs *fs) 597 { 598 Ndbtuple *t, *nt; 599 char *dev, *cons; 600 int cronly, speed, ondemand; 601 602 ndbreopen(db); 603 604 /* start a listener for each console */ 605 for(;;){ 606 t = ndbparse(db); 607 if(t == nil) 608 break; 609 dev = nil; 610 cons = nil; 611 speed = 9600; 612 cronly = 0; 613 ondemand = 0; 614 for(nt = t; nt; nt = nt->entry){ 615 if(strcmp(nt->attr, "console") == 0) 616 cons = nt->val; 617 else if(strcmp(nt->attr, "dev") == 0) 618 dev = nt->val; 619 else if(strcmp(nt->attr, "speed") == 0) 620 speed = atoi(nt->val); 621 else if(strcmp(nt->attr, "cronly") == 0) 622 cronly = 1; 623 else if(strcmp(nt->attr, "openondemand") == 0) 624 ondemand = 1; 625 } 626 if(dev != nil && cons != nil) 627 console(fs, cons, dev, speed, cronly, ondemand); 628 ndbfree(t); 629 } 630 } 631 632 int dbmtime; 633 634 /* 635 * a request processor (one per Fs) 636 */ 637 void 638 fsrun(void *v) 639 { 640 int n, t; 641 Request *r; 642 Fid *f; 643 Dir *d; 644 void **a = v; 645 Fs* fs; 646 int *pfd; 647 648 fs = a[0]; 649 pfd = a[1]; 650 fs->fd = pfd[0]; 651 for(;;){ 652 d = dirstat(consoledb); 653 if(d != nil && d->mtime != dbmtime){ 654 dbmtime = d->mtime; 655 readdb(fs); 656 } 657 free(d); 658 r = allocreq(fs, messagesize); 659 n = read9pmsg(fs->fd, r->buf, messagesize); 660 if(n <= 0) 661 fatal("unmounted"); 662 663 if(convM2S(r->buf, n, &r->f) == 0){ 664 fprint(2, "can't convert %ux %ux %ux\n", r->buf[0], 665 r->buf[1], r->buf[2]); 666 free(r); 667 continue; 668 } 669 670 671 f = fsgetfid(fs, r->f.fid); 672 r->fid = f; 673 if(debug) 674 fprint(2, "%F path %llux\n", &r->f, f->qid.path); 675 676 t = r->f.type; 677 r->f.type++; 678 (*fcall[t])(fs, r, f); 679 } 680 } 681 682 Fid* 683 fsgetfid(Fs *fs, int fid) 684 { 685 Fid *f, *nf; 686 687 lock(fs); 688 for(f = fs->hash[fid%Nhash]; f; f = f->next){ 689 if(f->fid == fid){ 690 f->ref++; 691 unlock(fs); 692 return f; 693 } 694 } 695 696 nf = emalloc(sizeof(Fid)); 697 nf->next = fs->hash[fid%Nhash]; 698 fs->hash[fid%Nhash] = nf; 699 nf->fid = fid; 700 nf->ref = 1; 701 nf->wp = nf->buf; 702 nf->rp = nf->wp; 703 unlock(fs); 704 return nf; 705 } 706 707 void 708 fsputfid(Fs *fs, Fid *f) 709 { 710 Fid **l, *nf; 711 712 lock(fs); 713 if(--f->ref > 0){ 714 unlock(fs); 715 return; 716 } 717 for(l = &fs->hash[f->fid%Nhash]; nf = *l; l = &nf->next) 718 if(nf == f){ 719 *l = f->next; 720 break; 721 } 722 unlock(fs); 723 free(f->user); 724 free(f); 725 } 726 727 728 void 729 fsauth(Fs *fs, Request *r, Fid*) 730 { 731 fsreply(fs, r, "consolefs: authentication not required"); 732 } 733 734 void 735 fsversion(Fs *fs, Request *r, Fid*) 736 { 737 738 if(r->f.msize < 256){ 739 fsreply(fs, r, "message size too small"); 740 return; 741 } 742 messagesize = r->f.msize; 743 if(messagesize > 8192+IOHDRSZ) 744 messagesize = 8192+IOHDRSZ; 745 r->f.msize = messagesize; 746 if(strncmp(r->f.version, "9P2000", 6) != 0){ 747 fsreply(fs, r, "unrecognized 9P version"); 748 return; 749 } 750 r->f.version = "9P2000"; 751 752 fsreply(fs, r, nil); 753 } 754 755 void 756 fsflush(Fs *fs, Request *r, Fid *f) 757 { 758 Request *or; 759 760 or = remtag(&f->r, r->f.oldtag); 761 if(or != nil){ 762 fsputfid(fs, or->fid); 763 free(or); 764 } 765 fsreply(fs, r, nil); 766 } 767 768 void 769 fsattach(Fs *fs, Request *r, Fid *f) 770 { 771 f->qid.type = QTDIR; 772 f->qid.path = QID(0, Ttopdir); 773 f->qid.vers = 0; 774 775 if(r->f.uname[0]) 776 f->user = strdup(r->f.uname); 777 else 778 f->user = strdup("none"); 779 780 /* hold down the fid till the clunk */ 781 f->attached = 1; 782 lock(fs); 783 f->ref++; 784 unlock(fs); 785 786 r->f.qid = f->qid; 787 fsreply(fs, r, nil); 788 } 789 790 void 791 fswalk(Fs *fs, Request *r, Fid *f) 792 { 793 char *name; 794 Dir d; 795 int i, n, nqid, nwname; 796 Qid qid, wqid[MAXWELEM]; 797 Fid *nf; 798 char *err; 799 800 if(f->attached == 0){ 801 fsreply(fs, r, Enofid); 802 return; 803 } 804 805 nf = nil; 806 if(r->f.fid != r->f.newfid){ 807 nf = fsgetfid(fs, r->f.newfid); 808 nf->attached = f->attached; 809 nf->open = f->open; 810 nf->qid = f->qid; 811 nf->user = strdup(f->user); 812 nf->c = f->c; 813 nf->wp = nf->buf; 814 nf->rp = nf->wp; 815 f = nf; 816 } 817 818 qid = f->qid; 819 err = nil; 820 nwname = r->f.nwname; 821 nqid = 0; 822 if(nwname > 0){ 823 for(; err == nil && nqid < nwname; nqid++){ 824 if(nqid >= MAXWELEM){ 825 err = "too many name elements"; 826 break; 827 } 828 name = r->f.wname[nqid]; 829 if(strcmp(name, "..") == 0) 830 qid = parentqid(qid); 831 else if(strcmp(name, ".") != 0){ 832 for(i = 0; ; i++){ 833 n = fsdirgen(fs, qid, i, &d, nil, 0); 834 if(n < 0){ 835 err = Eexist; 836 break; 837 } 838 if(n > 0 && strcmp(name, d.name) == 0){ 839 qid = d.qid; 840 break; 841 } 842 } 843 } 844 wqid[nqid] = qid; 845 } 846 if(nf != nil && nqid < nwname) 847 fsputfid(fs, nf); 848 if(nqid == nwname) 849 f->qid = qid; 850 } 851 852 memmove(r->f.wqid, wqid, nqid*sizeof(Qid)); 853 r->f.nwqid = nqid; 854 fsreply(fs, r, err); 855 } 856 857 int 858 ingroup(char *user, char *group) 859 { 860 Ndbtuple *t, *nt; 861 Ndbs s; 862 863 t = ndbsearch(db, &s, "group", group); 864 if(t == nil) 865 return 0; 866 for(nt = t; nt; nt = nt->entry){ 867 if(strcmp(nt->attr, "uid") == 0) 868 if(strcmp(nt->val, user) == 0) 869 break; 870 } 871 ndbfree(t); 872 return nt != nil; 873 } 874 875 int 876 userok(char *u, char *cname) 877 { 878 Ndbtuple *t, *nt; 879 Ndbs s; 880 881 t = ndbsearch(db, &s, "console", cname); 882 if(t == nil) 883 return 0; 884 885 for(nt = t; nt; nt = nt->entry){ 886 if(strcmp(nt->attr, "uid") == 0) 887 if(strcmp(nt->val, u) == 0) 888 break; 889 if(strcmp(nt->attr, "gid") == 0) 890 if(ingroup(u, nt->val)) 891 break; 892 } 893 ndbfree(t); 894 return nt != nil; 895 } 896 897 int m2p[] ={ 898 [OREAD] 4, 899 [OWRITE] 2, 900 [ORDWR] 6 901 }; 902 903 void 904 fsopen(Fs *fs, Request *r, Fid *f) 905 { 906 int mode; 907 Console *c; 908 909 if(f->attached == 0){ 910 fsreply(fs, r, Enofid); 911 return; 912 } 913 914 if(f->open){ 915 fsreply(fs, r, Eisopen); 916 return; 917 } 918 919 mode = r->f.mode & 3; 920 921 if((QTDIR & f->qid.type) && mode != OREAD){ 922 fsreply(fs, r, Eperm); 923 return; 924 } 925 926 switch(TYPE(f->qid)){ 927 case Qdata: 928 c = fs->cons[CONS(f->qid)]; 929 if(!userok(f->user, c->name)){ 930 fsreply(fs, r, Eperm); 931 return; 932 } 933 f->rp = f->buf; 934 f->wp = f->buf; 935 f->c = c; 936 lock(c); 937 f->cnext = c->flist; 938 c->flist = f; 939 bcastmembers(fs, c, "+", f); 940 if(c->pid == 0) 941 fsreopen(fs, c); 942 unlock(c); 943 break; 944 case Qctl: 945 c = fs->cons[CONS(f->qid)]; 946 if(!userok(f->user, c->name)){ 947 fsreply(fs, r, Eperm); 948 return; 949 } 950 f->c = c; 951 break; 952 case Qstat: 953 c = fs->cons[CONS(f->qid)]; 954 if(!userok(f->user, c->name)){ 955 fsreply(fs, r, Eperm); 956 return; 957 } 958 f->c = c; 959 break; 960 } 961 962 f->open = 1; 963 r->f.iounit = messagesize-IOHDRSZ; 964 r->f.qid = f->qid; 965 fsreply(fs, r, nil); 966 } 967 968 void 969 fscreate(Fs *fs, Request *r, Fid*) 970 { 971 fsreply(fs, r, Eperm); 972 } 973 974 void 975 fsread(Fs *fs, Request *r, Fid *f) 976 { 977 uchar *p, *e; 978 int i, m, off; 979 vlong offset; 980 Dir d; 981 char sbuf[ERRMAX]; 982 983 if(f->attached == 0){ 984 fsreply(fs, r, Enofid); 985 return; 986 } 987 988 if(r->f.count < 0){ 989 fsreply(fs, r, Ebadcount); 990 return; 991 } 992 993 if(QTDIR & f->qid.type){ 994 p = r->buf + IOHDRSZ; 995 e = p + r->f.count; 996 offset = r->f.offset; 997 off = 0; 998 for(i=0; p<e; i++, off+=m){ 999 m = fsdirgen(fs, f->qid, i, &d, p, e-p); 1000 if(m < 0) 1001 break; 1002 if(m > BIT16SZ && off >= offset) 1003 p += m; 1004 } 1005 r->f.data = (char*)r->buf + IOHDRSZ; 1006 r->f.count = (char*)p - r->f.data; 1007 } else { 1008 switch(TYPE(f->qid)){ 1009 case Qdata: 1010 addreq(&f->r, r); 1011 fskick(fs, f); 1012 return; 1013 case Qctl: 1014 r->f.data = (char*)r->buf+IOHDRSZ; 1015 r->f.count = 0; 1016 break; 1017 case Qstat: 1018 if(r->f.count > sizeof(sbuf)) 1019 r->f.count = sizeof(sbuf); 1020 i = pread(f->c->sfd, sbuf, r->f.count, r->f.offset); 1021 if(i < 0){ 1022 errstr(sbuf, sizeof sbuf); 1023 fsreply(fs, r, sbuf); 1024 return; 1025 } 1026 r->f.data = sbuf; 1027 r->f.count = i; 1028 break; 1029 default: 1030 fsreply(fs, r, Eexist); 1031 return; 1032 } 1033 } 1034 fsreply(fs, r, nil); 1035 } 1036 1037 void 1038 fswrite(Fs *fs, Request *r, Fid *f) 1039 { 1040 int i; 1041 1042 if(f->attached == 0){ 1043 fsreply(fs, r, Enofid); 1044 return; 1045 } 1046 1047 if(r->f.count < 0){ 1048 fsreply(fs, r, Ebadcount); 1049 return; 1050 } 1051 1052 if(QTDIR & f->qid.type){ 1053 fsreply(fs, r, Eperm); 1054 return; 1055 } 1056 1057 switch(TYPE(f->qid)){ 1058 default: 1059 fsreply(fs, r, Eperm); 1060 return; 1061 case Qctl: 1062 write(f->c->cfd, r->f.data, r->f.count); 1063 break; 1064 case Qdata: 1065 if(f->c->cronly) 1066 for(i = 0; i < r->f.count; i++) 1067 if(r->f.data[i] == '\n') 1068 r->f.data[i] = '\r'; 1069 write(f->c->fd, r->f.data, r->f.count); 1070 break; 1071 } 1072 fsreply(fs, r, nil); 1073 } 1074 1075 void 1076 fsclunk(Fs *fs, Request *r, Fid *f) 1077 { 1078 Fid **l, *fl; 1079 Request *nr; 1080 1081 if(f->open && TYPE(f->qid) == Qdata){ 1082 while((nr = remreq(&f->r)) != nil){ 1083 fsputfid(fs, f); 1084 free(nr); 1085 } 1086 1087 lock(f->c); 1088 for(l = &f->c->flist; *l; l = &fl->cnext){ 1089 fl = *l; 1090 if(fl == f){ 1091 *l = fl->cnext; 1092 break; 1093 } 1094 } 1095 bcastmembers(fs, f->c, "-", f); 1096 if(f->c->ondemand && f->c->flist == nil) 1097 fsreopen(fs, f->c); 1098 unlock(f->c); 1099 } 1100 fsreply(fs, r, nil); 1101 fsputfid(fs, f); 1102 } 1103 1104 void 1105 fsremove(Fs *fs, Request *r, Fid*) 1106 { 1107 fsreply(fs, r, Eperm); 1108 } 1109 1110 1111 void 1112 fsstat(Fs *fs, Request *r, Fid *f) 1113 { 1114 int i; 1115 Qid q; 1116 Dir d; 1117 1118 q = parentqid(f->qid); 1119 for(i = 0; ; i++){ 1120 r->f.stat = r->buf+IOHDRSZ; 1121 r->f.nstat = fsdirgen(fs, q, i, &d, r->f.stat, messagesize-IOHDRSZ); 1122 if(r->f.nstat < 0){ 1123 fsreply(fs, r, Eexist); 1124 return; 1125 } 1126 if(r->f.nstat > BIT16SZ && d.qid.path == f->qid.path) 1127 break; 1128 } 1129 fsreply(fs, r, nil); 1130 } 1131 1132 void 1133 fswstat(Fs *fs, Request *r, Fid*) 1134 { 1135 fsreply(fs, r, Eperm); 1136 } 1137 1138 void 1139 fsreply(Fs *fs, Request *r, char *err) 1140 { 1141 int n; 1142 uchar buf[8192+IOHDRSZ]; 1143 1144 if(err){ 1145 r->f.type = Rerror; 1146 r->f.ename = err; 1147 } 1148 n = convS2M(&r->f, buf, messagesize); 1149 if(debug) 1150 fprint(2, "%F path %llux n=%d\n", &r->f, r->fid->qid.path, n); 1151 fsputfid(fs, r->fid); 1152 if(write(fs->fd, buf, n) != n) 1153 fatal("unmounted"); 1154 free(r); 1155 } 1156 1157 /* 1158 * called whenever input or a read request has been received 1159 */ 1160 void 1161 fskick(Fs *fs, Fid *f) 1162 { 1163 Request *r; 1164 char *p, *rp, *wp, *ep; 1165 int i; 1166 1167 lock(f); 1168 while(f->rp != f->wp){ 1169 r = remreq(&f->r); 1170 if(r == nil) 1171 break; 1172 p = (char*)r->buf; 1173 rp = f->rp; 1174 wp = f->wp; 1175 ep = &f->buf[Bufsize]; 1176 for(i = 0; i < r->f.count && rp != wp; i++){ 1177 *p++ = *rp++; 1178 if(rp >= ep) 1179 rp = f->buf; 1180 } 1181 f->rp = rp; 1182 r->f.data = (char*)r->buf; 1183 r->f.count = p - (char*)r->buf; 1184 fsreply(fs, r, nil); 1185 } 1186 unlock(f); 1187 } 1188 1189 void 1190 usage(void) 1191 { 1192 fprint(2, "usage: consolefs [-d] [-m mount-point] [-c console-db]\n"); 1193 threadexitsall("usage"); 1194 } 1195 1196 void 1197 threadmain(int argc, char **argv) 1198 { 1199 fmtinstall('F', fcallfmt); 1200 1201 ARGBEGIN{ 1202 case 'd': 1203 debug++; 1204 break; 1205 case 'c': 1206 consoledb = ARGF(); 1207 if(consoledb == nil) 1208 usage(); 1209 break; 1210 case 'm': 1211 mntpt = ARGF(); 1212 if(mntpt == nil) 1213 usage(); 1214 break; 1215 }ARGEND; 1216 1217 db = ndbopen(consoledb); 1218 if(db == nil) 1219 fatal("can't open %s: %r", consoledb); 1220 1221 fsmount(mntpt); 1222 } 1223 1224