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 snprint(name, sizeof name, "%sctl", p); 303 p = name; 304 d->qid.type = QTFILE; 305 d->qid.path = QID(xcons, Qctl); 306 d->qid.vers = 0; 307 break; 308 case 1: 309 snprint(name, sizeof name, "%sstat", p); 310 p = name; 311 d->qid.type = QTFILE; 312 d->qid.path = QID(xcons, Qstat); 313 d->qid.vers = 0; 314 break; 315 case 2: 316 d->qid.type = QTFILE; 317 d->qid.path = QID(xcons, Qdata); 318 d->qid.vers = 0; 319 break; 320 } 321 d->mode = 0666; 322 break; 323 default: 324 return -1; 325 } 326 d->name = p; 327 if(buf != nil) 328 return convD2M(d, buf, nbuf); 329 return 0; 330 } 331 332 /* 333 * mount the user interface and start a request processor 334 */ 335 Fs* 336 fsmount(char *mntpt) 337 { 338 Fs *fs; 339 int pfd[2], srv; 340 char buf[32]; 341 int n; 342 static void *v[2]; 343 344 fs = emalloc(sizeof(Fs)); 345 346 if(pipe(pfd) < 0) 347 fatal("opening pipe: %r"); 348 349 /* start up the file system process */ 350 v[0] = fs; 351 v[1] = pfd; 352 proccreate(fsrun, v, 16*1024); 353 354 /* Typically mounted before /srv exists */ 355 if(access("#s/consoles", AEXIST) < 0){ 356 srv = create("#s/consoles", OWRITE, 0666); 357 if(srv < 0) 358 fatal("post: %r"); 359 360 n = sprint(buf, "%d", pfd[1]); 361 if(write(srv, buf, n) < 0) 362 fatal("write srv: %r"); 363 364 close(srv); 365 } 366 367 mount(pfd[1], -1, mntpt, MBEFORE, ""); 368 close(pfd[1]); 369 return fs; 370 } 371 372 /* 373 * reopen a console 374 */ 375 int 376 fsreopen(Fs* fs, Console *c) 377 { 378 char buf[128]; 379 static void *v[2]; 380 381 if(c->pid){ 382 if(postnote(PNPROC, c->pid, "reopen") != 0) 383 fprint(2, "postnote failed: %r\n"); 384 c->pid = 0; 385 } 386 387 if(c->fd >= 0){ 388 close(c->fd); 389 close(c->cfd); 390 close(c->sfd); 391 c->cfd = -1; 392 c->fd = -1; 393 c->sfd = -1; 394 } 395 396 if(c->flist == nil && c->ondemand) 397 return 0; 398 399 c->fd = open(c->dev, ORDWR); 400 if(c->fd < 0) 401 return -1; 402 403 snprint(buf, sizeof(buf), "%sctl", c->dev); 404 c->cfd = open(buf, ORDWR); 405 fprint(c->cfd, "b%d", c->speed); 406 407 snprint(buf, sizeof(buf), "%sstat", c->dev); 408 c->sfd = open(buf, OREAD); 409 410 v[0] = fs; 411 v[1] = c; 412 proccreate(fsreader, v, 16*1024); 413 414 return 0; 415 } 416 417 void 418 change(Fs *fs, Console *c, int doreopen, int speed, int cronly, int ondemand) 419 { 420 lock(c); 421 422 if(speed != c->speed){ 423 c->speed = speed; 424 doreopen = 1; 425 } 426 if(ondemand != c->ondemand){ 427 c->ondemand = ondemand; 428 doreopen = 1; 429 } 430 c->cronly = cronly; 431 if(doreopen) 432 fsreopen(fs, c); 433 434 unlock(c); 435 } 436 437 /* 438 * create a console interface 439 */ 440 void 441 console(Fs* fs, char *name, char *dev, int speed, int cronly, int ondemand) 442 { 443 Console *c; 444 char *x; 445 int i, doreopen; 446 447 if(fs->ncons >= Maxcons) 448 fatal("too many consoles, too little time"); 449 450 doreopen = 0; 451 for(i = 0; i < fs->ncons; i++){ 452 c = fs->cons[i]; 453 if(strcmp(name, c->name) == 0){ 454 if(strcmp(dev, c->dev) != 0){ 455 /* new device */ 456 x = c->dev; 457 c->dev = strdup(dev); 458 free(x); 459 doreopen = 1; 460 } 461 change(fs, c, doreopen, speed, cronly, ondemand); 462 return; 463 } 464 } 465 for(i = 0; i < fs->ncons; i++){ 466 c = fs->cons[i]; 467 if(strcmp(dev, c->dev) == 0){ 468 /* at least a rename */ 469 x = c->name; 470 c->name = strdup(name); 471 free(x); 472 change(fs, c, doreopen, speed, cronly, ondemand); 473 return; 474 } 475 } 476 477 c = emalloc(sizeof(Console)); 478 fs->cons[fs->ncons++] = c; 479 c->name = strdup(name); 480 c->dev = strdup(dev); 481 c->fd = -1; 482 c->cfd = -1; 483 c->sfd = -1; 484 change(fs, c, 1, speed, cronly, ondemand); 485 } 486 487 /* 488 * buffer data from console to a client. 489 * circular q with writer able to catch up to reader. 490 * the reader may miss data but always sees an in order sequence. 491 */ 492 void 493 fromconsole(Fid *f, char *p, int n) 494 { 495 char *rp, *wp, *ep; 496 int pass; 497 498 lock(f); 499 rp = f->rp; 500 wp = f->wp; 501 ep = f->buf + sizeof(f->buf); 502 pass = 0; 503 while(n--){ 504 *wp++ = *p++; 505 if(wp >= ep) 506 wp = f->buf; 507 if(rp == wp) 508 pass = 1; 509 } 510 f->wp = wp; 511 512 /* we overtook the read pointer, push it up so readers always 513 * see the tail of what was written 514 */ 515 if(pass){ 516 wp++; 517 if(wp >= ep) 518 f->rp = f->buf; 519 else 520 f->rp = wp; 521 } 522 unlock(f); 523 } 524 525 /* 526 * broadcast a list of members to all listeners 527 */ 528 void 529 bcastmembers(Fs *fs, Console *c, char *msg, Fid *f) 530 { 531 int n; 532 Fid *fl; 533 char buf[512]; 534 535 sprint(buf, "[%s%s", msg, f->user); 536 for(fl = c->flist; fl != nil && strlen(buf) + 64 < sizeof(buf); fl = fl->cnext){ 537 if(f == fl) 538 continue; 539 strcat(buf, ", "); 540 strcat(buf, fl->user); 541 } 542 strcat(buf, "]\n"); 543 544 n = strlen(buf); 545 for(fl = c->flist; fl; fl = fl->cnext){ 546 fromconsole(fl, buf, n); 547 fskick(fs, fl); 548 } 549 } 550 551 void 552 handler(void*, char *msg) 553 { 554 if(strstr(msg, "reopen")) 555 noted(NCONT); 556 noted(NDFLT); 557 } 558 559 560 /* 561 * a process to read console output and broadcast it (one per console) 562 */ 563 void 564 fsreader(void *v) 565 { 566 int n; 567 Fid *fl; 568 char buf[1024]; 569 Fs *fs; 570 Console *c; 571 void **a; 572 573 a = v; 574 fs = a[0]; 575 c = a[1]; 576 c->pid = getpid(); 577 notify(handler); 578 for(;;){ 579 n = read(c->fd, buf, sizeof(buf)); 580 if(n < 0) 581 break; 582 lock(c); 583 for(fl = c->flist; fl; fl = fl->cnext){ 584 fromconsole(fl, buf, n); 585 fskick(fs, fl); 586 } 587 unlock(c); 588 } 589 } 590 591 void 592 readdb(Fs *fs) 593 { 594 Ndbtuple *t, *nt; 595 char *dev, *cons; 596 int cronly, speed, ondemand; 597 598 ndbreopen(db); 599 600 /* start a listener for each console */ 601 for(;;){ 602 t = ndbparse(db); 603 if(t == nil) 604 break; 605 dev = nil; 606 cons = nil; 607 speed = 9600; 608 cronly = 0; 609 ondemand = 0; 610 for(nt = t; nt; nt = nt->entry){ 611 if(strcmp(nt->attr, "console") == 0) 612 cons = nt->val; 613 else if(strcmp(nt->attr, "dev") == 0) 614 dev = nt->val; 615 else if(strcmp(nt->attr, "speed") == 0) 616 speed = atoi(nt->val); 617 else if(strcmp(nt->attr, "cronly") == 0) 618 cronly = 1; 619 else if(strcmp(nt->attr, "openondemand") == 0) 620 ondemand = 1; 621 } 622 if(dev != nil && cons != nil) 623 console(fs, cons, dev, speed, cronly, ondemand); 624 ndbfree(t); 625 } 626 } 627 628 int dbmtime; 629 630 /* 631 * a request processor (one per Fs) 632 */ 633 void 634 fsrun(void *v) 635 { 636 int n, t; 637 Request *r; 638 Fid *f; 639 Dir *d; 640 void **a = v; 641 Fs* fs; 642 int *pfd; 643 644 fs = a[0]; 645 pfd = a[1]; 646 fs->fd = pfd[0]; 647 for(;;){ 648 d = dirstat(consoledb); 649 if(d != nil && d->mtime != dbmtime){ 650 dbmtime = d->mtime; 651 readdb(fs); 652 } 653 free(d); 654 r = allocreq(fs, messagesize); 655 n = read9pmsg(fs->fd, r->buf, messagesize); 656 if(n <= 0) 657 fatal("unmounted"); 658 659 if(convM2S(r->buf, n, &r->f) == 0){ 660 fprint(2, "can't convert %ux %ux %ux\n", r->buf[0], 661 r->buf[1], r->buf[2]); 662 free(r); 663 continue; 664 } 665 666 667 f = fsgetfid(fs, r->f.fid); 668 r->fid = f; 669 if(debug) 670 fprint(2, "%F path %llux\n", &r->f, f->qid.path); 671 672 t = r->f.type; 673 r->f.type++; 674 (*fcall[t])(fs, r, f); 675 } 676 } 677 678 Fid* 679 fsgetfid(Fs *fs, int fid) 680 { 681 Fid *f, *nf; 682 683 lock(fs); 684 for(f = fs->hash[fid%Nhash]; f; f = f->next){ 685 if(f->fid == fid){ 686 f->ref++; 687 unlock(fs); 688 return f; 689 } 690 } 691 692 nf = emalloc(sizeof(Fid)); 693 nf->next = fs->hash[fid%Nhash]; 694 fs->hash[fid%Nhash] = nf; 695 nf->fid = fid; 696 nf->ref = 1; 697 nf->wp = nf->buf; 698 nf->rp = nf->wp; 699 unlock(fs); 700 return nf; 701 } 702 703 void 704 fsputfid(Fs *fs, Fid *f) 705 { 706 Fid **l, *nf; 707 708 lock(fs); 709 if(--f->ref > 0){ 710 unlock(fs); 711 return; 712 } 713 for(l = &fs->hash[f->fid%Nhash]; nf = *l; l = &nf->next) 714 if(nf == f){ 715 *l = f->next; 716 break; 717 } 718 unlock(fs); 719 free(f->user); 720 free(f); 721 } 722 723 724 void 725 fsauth(Fs *fs, Request *r, Fid*) 726 { 727 fsreply(fs, r, "consolefs: authentication not required"); 728 } 729 730 void 731 fsversion(Fs *fs, Request *r, Fid*) 732 { 733 734 if(r->f.msize < 256){ 735 fsreply(fs, r, "message size too small"); 736 return; 737 } 738 messagesize = r->f.msize; 739 if(messagesize > 8192+IOHDRSZ) 740 messagesize = 8192+IOHDRSZ; 741 r->f.msize = messagesize; 742 if(strncmp(r->f.version, "9P2000", 6) != 0){ 743 fsreply(fs, r, "unrecognized 9P version"); 744 return; 745 } 746 r->f.version = "9P2000"; 747 748 fsreply(fs, r, nil); 749 } 750 751 void 752 fsflush(Fs *fs, Request *r, Fid *f) 753 { 754 Request *or; 755 756 or = remtag(&f->r, r->f.oldtag); 757 if(or != nil){ 758 fsputfid(fs, or->fid); 759 free(or); 760 } 761 fsreply(fs, r, nil); 762 } 763 764 void 765 fsattach(Fs *fs, Request *r, Fid *f) 766 { 767 f->qid.type = QTDIR; 768 f->qid.path = QID(0, Ttopdir); 769 f->qid.vers = 0; 770 771 if(r->f.uname[0]) 772 f->user = strdup(r->f.uname); 773 else 774 f->user = strdup("none"); 775 776 /* hold down the fid till the clunk */ 777 f->attached = 1; 778 lock(fs); 779 f->ref++; 780 unlock(fs); 781 782 r->f.qid = f->qid; 783 fsreply(fs, r, nil); 784 } 785 786 void 787 fswalk(Fs *fs, Request *r, Fid *f) 788 { 789 char *name; 790 Dir d; 791 int i, nqid, nwname; 792 Qid qid, wqid[MAXWELEM]; 793 Fid *nf; 794 char *err; 795 796 if(f->attached == 0){ 797 fsreply(fs, r, Enofid); 798 return; 799 } 800 801 nf = nil; 802 if(r->f.fid != r->f.newfid){ 803 nf = fsgetfid(fs, r->f.newfid); 804 nf->attached = f->attached; 805 nf->open = f->open; 806 nf->qid = f->qid; 807 nf->user = strdup(f->user); 808 nf->c = f->c; 809 nf->wp = nf->buf; 810 nf->rp = nf->wp; 811 f = nf; 812 } 813 814 qid = f->qid; 815 err = nil; 816 nwname = r->f.nwname; 817 nqid = 0; 818 if(nwname > 0){ 819 for(; err == nil && nqid < nwname; nqid++){ 820 if(nqid >= MAXWELEM){ 821 err = "too many name elements"; 822 break; 823 } 824 name = r->f.wname[nqid]; 825 if(strcmp(name, "..") == 0) 826 qid = parentqid(qid); 827 else if(strcmp(name, ".") != 0){ 828 for(i = 0; ; i++){ 829 if(fsdirgen(fs, qid, i, &d, nil, 0) < 0){ 830 err = Eexist; 831 break; 832 } 833 if(strcmp(name, d.name) == 0){ 834 qid = d.qid; 835 break; 836 } 837 } 838 } 839 wqid[nqid] = qid; 840 } 841 if(nf != nil && nqid < nwname) 842 fsputfid(fs, nf); 843 if(nqid == nwname) 844 f->qid = qid; 845 } 846 847 memmove(r->f.wqid, wqid, nqid*sizeof(Qid)); 848 r->f.nwqid = nqid; 849 fsreply(fs, r, err); 850 } 851 852 int 853 ingroup(char *user, char *group) 854 { 855 Ndbtuple *t, *nt; 856 Ndbs s; 857 858 t = ndbsearch(db, &s, "group", group); 859 if(t == nil) 860 return 0; 861 for(nt = t; nt; nt = nt->entry){ 862 if(strcmp(nt->attr, "uid") == 0) 863 if(strcmp(nt->val, user) == 0) 864 break; 865 } 866 ndbfree(t); 867 return nt != nil; 868 } 869 870 int 871 userok(char *u, char *cname) 872 { 873 Ndbtuple *t, *nt; 874 Ndbs s; 875 876 t = ndbsearch(db, &s, "console", cname); 877 if(t == nil) 878 return 0; 879 880 for(nt = t; nt; nt = nt->entry){ 881 if(strcmp(nt->attr, "uid") == 0) 882 if(strcmp(nt->val, u) == 0) 883 break; 884 if(strcmp(nt->attr, "gid") == 0) 885 if(ingroup(u, nt->val)) 886 break; 887 } 888 ndbfree(t); 889 return nt != nil; 890 } 891 892 int m2p[] ={ 893 [OREAD] 4, 894 [OWRITE] 2, 895 [ORDWR] 6 896 }; 897 898 void 899 fsopen(Fs *fs, Request *r, Fid *f) 900 { 901 int mode; 902 Console *c; 903 904 if(f->attached == 0){ 905 fsreply(fs, r, Enofid); 906 return; 907 } 908 909 if(f->open){ 910 fsreply(fs, r, Eisopen); 911 return; 912 } 913 914 mode = r->f.mode & 3; 915 916 if((QTDIR & f->qid.type) && mode != OREAD){ 917 fsreply(fs, r, Eperm); 918 return; 919 } 920 921 switch(TYPE(f->qid)){ 922 case Qdata: 923 c = fs->cons[CONS(f->qid)]; 924 if(!userok(f->user, c->name)){ 925 fsreply(fs, r, Eperm); 926 return; 927 } 928 f->rp = f->buf; 929 f->wp = f->buf; 930 f->c = c; 931 lock(c); 932 f->cnext = c->flist; 933 c->flist = f; 934 bcastmembers(fs, c, "+", f); 935 if(c->pid == 0) 936 fsreopen(fs, c); 937 unlock(c); 938 break; 939 case Qctl: 940 c = fs->cons[CONS(f->qid)]; 941 if(!userok(f->user, c->name)){ 942 fsreply(fs, r, Eperm); 943 return; 944 } 945 f->c = c; 946 break; 947 case Qstat: 948 c = fs->cons[CONS(f->qid)]; 949 if(!userok(f->user, c->name)){ 950 fsreply(fs, r, Eperm); 951 return; 952 } 953 f->c = c; 954 break; 955 } 956 957 f->open = 1; 958 r->f.iounit = messagesize-IOHDRSZ; 959 r->f.qid = f->qid; 960 fsreply(fs, r, nil); 961 } 962 963 void 964 fscreate(Fs *fs, Request *r, Fid*) 965 { 966 fsreply(fs, r, Eperm); 967 } 968 969 void 970 fsread(Fs *fs, Request *r, Fid *f) 971 { 972 uchar *p, *e; 973 int i, m, off; 974 vlong offset; 975 Dir d; 976 char sbuf[ERRMAX]; 977 978 if(f->attached == 0){ 979 fsreply(fs, r, Enofid); 980 return; 981 } 982 983 if(r->f.count < 0){ 984 fsreply(fs, r, Ebadcount); 985 return; 986 } 987 988 if(QTDIR & f->qid.type){ 989 p = r->buf + IOHDRSZ; 990 e = p + r->f.count; 991 offset = r->f.offset; 992 off = 0; 993 for(i=0; p<e; i++, off+=m){ 994 m = fsdirgen(fs, f->qid, i, &d, p, e-p); 995 if(m <= BIT16SZ) 996 break; 997 if(off >= offset) 998 p += m; 999 } 1000 r->f.data = (char*)r->buf + IOHDRSZ; 1001 r->f.count = (char*)p - r->f.data; 1002 } else { 1003 switch(TYPE(f->qid)){ 1004 case Qdata: 1005 addreq(&f->r, r); 1006 fskick(fs, f); 1007 return; 1008 case Qctl: 1009 r->f.data = (char*)r->buf+IOHDRSZ; 1010 r->f.count = 0; 1011 break; 1012 case Qstat: 1013 if(r->f.count > sizeof(sbuf)) 1014 r->f.count = sizeof(sbuf); 1015 i = pread(f->c->sfd, sbuf, r->f.count, r->f.offset); 1016 if(i < 0){ 1017 errstr(sbuf, sizeof sbuf); 1018 fsreply(fs, r, sbuf); 1019 return; 1020 } 1021 r->f.data = sbuf; 1022 r->f.count = i; 1023 break; 1024 default: 1025 fsreply(fs, r, Eexist); 1026 return; 1027 } 1028 } 1029 fsreply(fs, r, nil); 1030 } 1031 1032 void 1033 fswrite(Fs *fs, Request *r, Fid *f) 1034 { 1035 int i; 1036 1037 if(f->attached == 0){ 1038 fsreply(fs, r, Enofid); 1039 return; 1040 } 1041 1042 if(r->f.count < 0){ 1043 fsreply(fs, r, Ebadcount); 1044 return; 1045 } 1046 1047 if(QTDIR & f->qid.type){ 1048 fsreply(fs, r, Eperm); 1049 return; 1050 } 1051 1052 switch(TYPE(f->qid)){ 1053 default: 1054 fsreply(fs, r, Eperm); 1055 return; 1056 case Qctl: 1057 write(f->c->cfd, r->f.data, r->f.count); 1058 break; 1059 case Qdata: 1060 if(f->c->cronly) 1061 for(i = 0; i < r->f.count; i++) 1062 if(r->f.data[i] == '\n') 1063 r->f.data[i] = '\r'; 1064 write(f->c->fd, r->f.data, r->f.count); 1065 break; 1066 } 1067 fsreply(fs, r, nil); 1068 } 1069 1070 void 1071 fsclunk(Fs *fs, Request *r, Fid *f) 1072 { 1073 Fid **l, *fl; 1074 Request *nr; 1075 1076 if(f->open && TYPE(f->qid) == Qdata){ 1077 while((nr = remreq(&f->r)) != nil){ 1078 fsputfid(fs, f); 1079 free(nr); 1080 } 1081 1082 lock(f->c); 1083 for(l = &f->c->flist; *l; l = &fl->cnext){ 1084 fl = *l; 1085 if(fl == f){ 1086 *l = fl->cnext; 1087 break; 1088 } 1089 } 1090 bcastmembers(fs, f->c, "-", f); 1091 if(f->c->ondemand && f->c->flist == nil) 1092 fsreopen(fs, f->c); 1093 unlock(f->c); 1094 } 1095 fsreply(fs, r, nil); 1096 fsputfid(fs, f); 1097 } 1098 1099 void 1100 fsremove(Fs *fs, Request *r, Fid*) 1101 { 1102 fsreply(fs, r, Eperm); 1103 } 1104 1105 1106 void 1107 fsstat(Fs *fs, Request *r, Fid *f) 1108 { 1109 int i; 1110 Qid q; 1111 Dir d; 1112 1113 q = parentqid(f->qid); 1114 for(i = 0; ; i++){ 1115 r->f.stat = r->buf+IOHDRSZ; 1116 if((r->f.nstat = fsdirgen(fs, q, i, &d, r->f.stat, messagesize-IOHDRSZ)) <= BIT16SZ){ 1117 fsreply(fs, r, Eexist); 1118 return; 1119 } 1120 if(d.qid.path == f->qid.path) 1121 break; 1122 } 1123 fsreply(fs, r, nil); 1124 } 1125 1126 void 1127 fswstat(Fs *fs, Request *r, Fid*) 1128 { 1129 fsreply(fs, r, Eperm); 1130 } 1131 1132 void 1133 fsreply(Fs *fs, Request *r, char *err) 1134 { 1135 int n; 1136 uchar buf[8192+IOHDRSZ]; 1137 1138 if(err){ 1139 r->f.type = Rerror; 1140 r->f.ename = err; 1141 } 1142 n = convS2M(&r->f, buf, messagesize); 1143 if(debug) 1144 fprint(2, "%F path %llux n=%d\n", &r->f, r->fid->qid.path, n); 1145 fsputfid(fs, r->fid); 1146 if(write(fs->fd, buf, n) != n) 1147 fatal("unmounted"); 1148 free(r); 1149 } 1150 1151 /* 1152 * called whenever input or a read request has been received 1153 */ 1154 void 1155 fskick(Fs *fs, Fid *f) 1156 { 1157 Request *r; 1158 char *p, *rp, *wp, *ep; 1159 int i; 1160 1161 lock(f); 1162 while(f->rp != f->wp){ 1163 r = remreq(&f->r); 1164 if(r == nil) 1165 break; 1166 p = (char*)r->buf; 1167 rp = f->rp; 1168 wp = f->wp; 1169 ep = &f->buf[Bufsize]; 1170 for(i = 0; i < r->f.count && rp != wp; i++){ 1171 *p++ = *rp++; 1172 if(rp >= ep) 1173 rp = f->buf; 1174 } 1175 f->rp = rp; 1176 r->f.data = (char*)r->buf; 1177 r->f.count = p - (char*)r->buf; 1178 fsreply(fs, r, nil); 1179 } 1180 unlock(f); 1181 } 1182 1183 void 1184 usage(void) 1185 { 1186 fprint(2, "usage: consolefs [-d] [-m mount-point] [-c console-db]\n"); 1187 threadexitsall("usage"); 1188 } 1189 1190 void 1191 threadmain(int argc, char **argv) 1192 { 1193 fmtinstall('F', fcallfmt); 1194 1195 ARGBEGIN{ 1196 case 'd': 1197 debug++; 1198 break; 1199 case 'c': 1200 consoledb = ARGF(); 1201 if(consoledb == nil) 1202 usage(); 1203 break; 1204 case 'm': 1205 mntpt = ARGF(); 1206 if(mntpt == nil) 1207 usage(); 1208 break; 1209 }ARGEND; 1210 1211 db = ndbopen(consoledb); 1212 if(db == nil) 1213 fatal("can't open %s: %r", consoledb); 1214 1215 fsmount(mntpt); 1216 } 1217 1218