1 /* 2 * cpu.c - Make a connection to a cpu server 3 * 4 * Invoked by listen as 'cpu -R | -N service net netdir' 5 * by users as 'cpu [-h system] [-c cmd args ...]' 6 */ 7 8 #include <u.h> 9 #include <libc.h> 10 #include <bio.h> 11 #include <auth.h> 12 #include <fcall.h> 13 #include <libsec.h> 14 15 #define Maxfdata 8192 16 17 void remoteside(int); 18 void fatal(int, char*, ...); 19 void lclnoteproc(int); 20 void rmtnoteproc(void); 21 void catcher(void*, char*); 22 void usage(void); 23 void writestr(int, char*, char*, int); 24 int readstr(int, char*, int); 25 char *rexcall(int*, char*, char*); 26 int setamalg(char*); 27 28 int notechan; 29 char system[32]; 30 int cflag; 31 int hflag; 32 int dbg; 33 char *user; 34 35 char *srvname = "ncpu"; 36 char *exportfs = "/bin/exportfs"; 37 char *ealgs = "rc4_256 sha1"; 38 39 /* message size for exportfs; may be larger so we can do big graphics in CPU window */ 40 int msgsize = Maxfdata+IOHDRSZ; 41 42 /* authentication mechanisms */ 43 static int netkeyauth(int); 44 static int netkeysrvauth(int, char*); 45 static int p9auth(int); 46 static int srvp9auth(int, char*); 47 static int noauth(int); 48 static int srvnoauth(int, char*); 49 50 typedef struct AuthMethod AuthMethod; 51 struct AuthMethod { 52 char *name; /* name of method */ 53 int (*cf)(int); /* client side authentication */ 54 int (*sf)(int, char*); /* server side authentication */ 55 } authmethod[] = 56 { 57 { "p9", p9auth, srvp9auth,}, 58 { "netkey", netkeyauth, netkeysrvauth,}, 59 // { "none", noauth, srvnoauth,}, 60 { nil, nil} 61 }; 62 AuthMethod *am = authmethod; /* default is p9 */ 63 64 char *p9authproto = "p9any"; 65 66 int setam(char*); 67 68 void 69 usage(void) 70 { 71 fprint(2, "usage: cpu [-h system] [-a authmethod] [-e 'crypt hash'] [-c cmd args ...]\n"); 72 exits("usage"); 73 } 74 int fdd; 75 76 void 77 main(int argc, char **argv) 78 { 79 char dat[128], buf[128], cmd[128], *p, *err; 80 int fd, ms, data; 81 82 /* see if we should use a larger message size */ 83 fd = open("/dev/draw", OREAD); 84 if(fd > 0){ 85 ms = iounit(fd); 86 if(msgsize < ms+IOHDRSZ) 87 msgsize = ms+IOHDRSZ; 88 close(fd); 89 } 90 91 user = getuser(); 92 if(user == nil) 93 fatal(1, "can't read user name"); 94 ARGBEGIN{ 95 case 'a': 96 p = EARGF(usage()); 97 if(setam(p) < 0) 98 fatal(0, "unknown auth method %s", p); 99 break; 100 case 'e': 101 ealgs = EARGF(usage()); 102 if(*ealgs == 0 || strcmp(ealgs, "clear") == 0) 103 ealgs = nil; 104 break; 105 case 'd': 106 dbg++; 107 break; 108 case 'f': 109 /* ignored but accepted for compatibility */ 110 break; 111 case 'O': 112 p9authproto = "p9sk2"; 113 remoteside(1); /* From listen */ 114 break; 115 case 'R': /* From listen */ 116 remoteside(0); 117 break; 118 case 'h': 119 hflag++; 120 p = EARGF(usage()); 121 strcpy(system, p); 122 break; 123 case 'c': 124 cflag++; 125 cmd[0] = '!'; 126 cmd[1] = '\0'; 127 while(p = ARGF()) { 128 strcat(cmd, " "); 129 strcat(cmd, p); 130 } 131 break; 132 default: 133 usage(); 134 }ARGEND; 135 136 137 if(argc != 0) 138 usage(); 139 140 if(hflag == 0) { 141 p = getenv("cpu"); 142 if(p == 0) 143 fatal(0, "set $cpu"); 144 strcpy(system, p); 145 } 146 147 if(err = rexcall(&data, system, srvname)) 148 fatal(1, "%s: %s", err, system); 149 150 /* Tell the remote side the command to execute and where our working directory is */ 151 if(cflag) 152 writestr(data, cmd, "command", 0); 153 if(getwd(dat, sizeof(dat)) == 0) 154 writestr(data, "NO", "dir", 0); 155 else 156 writestr(data, dat, "dir", 0); 157 158 /* start up a process to pass along notes */ 159 lclnoteproc(data); 160 161 /* 162 * Wait for the other end to execute and start our file service 163 * of /mnt/term 164 */ 165 if(readstr(data, buf, sizeof(buf)) < 0) 166 fatal(1, "waiting for FS"); 167 if(strncmp("FS", buf, 2) != 0) { 168 print("remote cpu: %s", buf); 169 exits(buf); 170 } 171 172 /* Begin serving the gnot namespace */ 173 close(0); 174 dup(data, 0); 175 close(data); 176 sprint(buf, "%d", msgsize); 177 if(dbg) 178 execl(exportfs, exportfs, "-dm", buf, 0); 179 else 180 execl(exportfs, exportfs, "-m", buf, 0); 181 fatal(1, "starting exportfs"); 182 } 183 184 void 185 fatal(int syserr, char *fmt, ...) 186 { 187 Fmt f; 188 char *str; 189 va_list arg; 190 191 fmtstrinit(&f); 192 fmtprint(&f, "cpu: "); 193 va_start(arg, fmt); 194 fmtvprint(&f, fmt, arg); 195 va_end(arg); 196 if(syserr) 197 fmtprint(&f, ": %r"); 198 fmtprint(&f, "\n"); 199 str = fmtstrflush(&f); 200 write(2, str, strlen(str)); 201 exits(str); 202 } 203 204 char *negstr = "negotiating authentication method"; 205 206 char bug[256]; 207 208 int 209 old9p(int fd) 210 { 211 int p[2]; 212 213 if(pipe(p) < 0) 214 fatal(1, "pipe"); 215 216 switch(rfork(RFPROC|RFFDG|RFNAMEG)) { 217 case -1: 218 fatal(1, "rfork srvold9p"); 219 case 0: 220 if(fd != 1){ 221 dup(fd, 1); 222 close(fd); 223 } 224 if(p[0] != 0){ 225 dup(p[0], 0); 226 close(p[0]); 227 } 228 close(p[1]); 229 if(0){ 230 fd = open("/sys/log/cpu", OWRITE); 231 if(fd != 2){ 232 dup(fd, 2); 233 close(fd); 234 } 235 execl("/bin/srvold9p", "srvold9p", "-ds", 0); 236 } else 237 execl("/bin/srvold9p", "srvold9p", "-s", 0); 238 fatal(1, "exec srvold9p"); 239 default: 240 close(fd); 241 close(p[0]); 242 } 243 return p[1]; 244 } 245 246 /* Invoked with stdin, stdout and stderr connected to the network connection */ 247 void 248 remoteside(int old) 249 { 250 char user[128], home[128], buf[128], xdir[128], cmd[128]; 251 int i, n, fd, badchdir, gotcmd; 252 253 fd = 0; 254 255 /* negotiate authentication mechanism */ 256 n = readstr(fd, cmd, sizeof(cmd)); 257 if(n < 0) 258 fatal(1, "authenticating"); 259 if(setamalg(cmd) < 0){ 260 writestr(fd, "unsupported auth method", nil, 0); 261 fatal(1, "bad auth method %s", cmd); 262 } else 263 writestr(fd, "", "", 1); 264 265 fd = (*am->sf)(fd, user); 266 if(fd < 0) 267 fatal(1, "srvauth"); 268 269 /* Set environment values for the user */ 270 putenv("user", user); 271 sprint(home, "/usr/%s", user); 272 putenv("home", home); 273 274 /* Now collect invoking cpu's current directory or possibly a command */ 275 gotcmd = 0; 276 if(readstr(fd, xdir, sizeof(xdir)) < 0) 277 fatal(1, "dir/cmd"); 278 if(xdir[0] == '!') { 279 strcpy(cmd, &xdir[1]); 280 gotcmd = 1; 281 if(readstr(fd, xdir, sizeof(xdir)) < 0) 282 fatal(1, "dir"); 283 } 284 285 /* Establish the new process at the current working directory of the 286 * gnot */ 287 badchdir = 0; 288 if(strcmp(xdir, "NO") == 0) 289 chdir(home); 290 else if(chdir(xdir) < 0) { 291 badchdir = 1; 292 chdir(home); 293 } 294 295 /* Start the gnot serving its namespace */ 296 writestr(fd, "FS", "FS", 0); 297 writestr(fd, "/", "exportfs dir", 0); 298 299 n = read(fd, buf, sizeof(buf)); 300 if(n != 2 || buf[0] != 'O' || buf[1] != 'K') 301 exits("remote tree"); 302 303 if(old) 304 fd = old9p(fd); 305 306 /* make sure buffers are big by doing fversion explicitly; pick a huge number; other side will trim */ 307 strcpy(buf, VERSION9P); 308 if(fversion(fd, 64*1024, buf, sizeof buf) < 0) 309 exits("fversion failed"); 310 if(mount(fd, -1, "/mnt/term", MCREATE|MREPL, "") < 0) 311 exits("mount failed"); 312 313 close(fd); 314 315 /* the remote noteproc uses the mount so it must follow it */ 316 rmtnoteproc(); 317 318 for(i = 0; i < 3; i++) 319 close(i); 320 321 if(open("/mnt/term/dev/cons", OREAD) != 0) 322 exits("open stdin"); 323 if(open("/mnt/term/dev/cons", OWRITE) != 1) 324 exits("open stdout"); 325 dup(1, 2); 326 327 if(badchdir) 328 print("cpu: failed to chdir to '%s'\n", xdir); 329 330 if(gotcmd) 331 execl("/bin/rc", "rc", "-lc", cmd, 0); 332 else 333 execl("/bin/rc", "rc", "-li", 0); 334 fatal(1, "exec shell"); 335 } 336 337 char* 338 rexcall(int *fd, char *host, char *service) 339 { 340 char *na; 341 char dir[128]; 342 char err[ERRMAX]; 343 char msg[128]; 344 int n; 345 346 na = netmkaddr(host, 0, service); 347 if((*fd = dial(na, 0, dir, 0)) < 0) 348 return "can't dial"; 349 350 /* negotiate authentication mechanism */ 351 if(ealgs != nil) 352 snprint(msg, sizeof(msg), "%s %s", am->name, ealgs); 353 else 354 snprint(msg, sizeof(msg), "%s", am->name); 355 writestr(*fd, msg, negstr, 0); 356 n = readstr(*fd, err, sizeof err); 357 if(n < 0) 358 return negstr; 359 if(*err){ 360 werrstr(err); 361 return negstr; 362 } 363 364 /* authenticate */ 365 *fd = (*am->cf)(*fd); 366 if(*fd < 0) 367 return "can't authenticate"; 368 return 0; 369 } 370 371 void 372 writestr(int fd, char *str, char *thing, int ignore) 373 { 374 int l, n; 375 376 l = strlen(str); 377 n = write(fd, str, l+1); 378 if(!ignore && n < 0) 379 fatal(1, "writing network: %s", thing); 380 } 381 382 int 383 readstr(int fd, char *str, int len) 384 { 385 int n; 386 387 while(len) { 388 n = read(fd, str, 1); 389 if(n < 0) 390 return -1; 391 if(*str == '\0') 392 return 0; 393 str++; 394 len--; 395 } 396 return -1; 397 } 398 399 static int 400 readln(char *buf, int n) 401 { 402 int i; 403 char *p; 404 405 n--; /* room for \0 */ 406 p = buf; 407 for(i=0; i<n; i++){ 408 if(read(0, p, 1) != 1) 409 break; 410 if(*p == '\n' || *p == '\r') 411 break; 412 p++; 413 } 414 *p = '\0'; 415 return p-buf; 416 } 417 418 /* 419 * user level challenge/response 420 */ 421 static int 422 netkeyauth(int fd) 423 { 424 char chall[32]; 425 char resp[32]; 426 427 strcpy(chall, getuser()); 428 print("user[%s]: ", chall); 429 if(readln(resp, sizeof(resp)) < 0) 430 return -1; 431 if(*resp != 0) 432 strcpy(chall, resp); 433 writestr(fd, chall, "challenge/response", 1); 434 435 for(;;){ 436 if(readstr(fd, chall, sizeof chall) < 0) 437 break; 438 if(*chall == 0) 439 return fd; 440 print("challenge: %s\nresponse: ", chall); 441 if(readln(resp, sizeof(resp)) < 0) 442 break; 443 writestr(fd, resp, "challenge/response", 1); 444 } 445 return -1; 446 } 447 448 static int 449 netkeysrvauth(int fd, char *user) 450 { 451 char response[32]; 452 Chalstate *ch; 453 int tries; 454 AuthInfo *ai; 455 456 if(readstr(fd, user, 32) < 0) 457 return -1; 458 459 ai = nil; 460 ch = nil; 461 for(tries = 0; tries < 10; tries++){ 462 if((ch = auth_challenge("proto=p9cr role=server user=%q", user)) == nil) 463 return -1; 464 writestr(fd, ch->chal, "challenge", 1); 465 if(readstr(fd, response, sizeof response) < 0) 466 return -1; 467 ch->resp = response; 468 ch->nresp = strlen(response); 469 if((ai = auth_response(ch)) != nil) 470 break; 471 } 472 auth_freechal(ch); 473 if(ai == nil) 474 return -1; 475 writestr(fd, "", "challenge", 1); 476 if(auth_chuid(ai, 0) < 0) 477 fatal(1, "newns"); 478 auth_freeAI(ai); 479 return fd; 480 } 481 482 static void 483 mksecret(char *t, uchar *f) 484 { 485 sprint(t, "%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux", 486 f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9]); 487 } 488 489 /* 490 * plan9 authentication followed by rc4 encryption 491 */ 492 static int 493 p9auth(int fd) 494 { 495 uchar key[16]; 496 uchar digest[SHA1dlen]; 497 char fromclientsecret[21]; 498 char fromserversecret[21]; 499 int i; 500 AuthInfo *ai; 501 502 ai = auth_proxy(fd, auth_getkey, "proto=%q role=client", p9authproto); 503 if(ai == nil) 504 return -1; 505 memmove(key+4, ai->secret, ai->nsecret); 506 if(ealgs == nil) 507 return fd; 508 509 /* exchange random numbers */ 510 srand(truerand()); 511 for(i = 0; i < 4; i++) 512 key[i] = rand(); 513 if(write(fd, key, 4) != 4) 514 return -1; 515 if(readn(fd, key+12, 4) != 4) 516 return -1; 517 518 /* scramble into two secrets */ 519 sha1(key, sizeof(key), digest, nil); 520 mksecret(fromclientsecret, digest); 521 mksecret(fromserversecret, digest+10); 522 523 /* set up encryption */ 524 i = pushssl(fd, ealgs, fromclientsecret, fromserversecret, nil); 525 if(i < 0) 526 werrstr("can't establish ssl connection: %r"); 527 return i; 528 } 529 530 static int 531 noauth(int fd) 532 { 533 ealgs = nil; 534 return fd; 535 } 536 537 static int 538 srvnoauth(int fd, char *user) 539 { 540 strcpy(user, getuser()); 541 ealgs = nil; 542 return fd; 543 } 544 545 void 546 loghex(uchar *p, int n) 547 { 548 char buf[100]; 549 int i; 550 551 for(i = 0; i < n; i++) 552 sprint(buf+2*i, "%2.2ux", p[i]); 553 syslog(0, "cpu", buf); 554 } 555 556 static int 557 srvp9auth(int fd, char *user) 558 { 559 uchar key[16]; 560 uchar digest[SHA1dlen]; 561 char fromclientsecret[21]; 562 char fromserversecret[21]; 563 int i; 564 AuthInfo *ai; 565 566 ai = auth_proxy(0, nil, "proto=%q role=server", p9authproto); 567 if(ai == nil) 568 return -1; 569 if(auth_chuid(ai, nil) < 0) 570 return -1; 571 strcpy(user, ai->cuid); 572 memmove(key+4, ai->secret, ai->nsecret); 573 574 if(ealgs == nil) 575 return fd; 576 577 /* exchange random numbers */ 578 srand(truerand()); 579 for(i = 0; i < 4; i++) 580 key[i+12] = rand(); 581 if(readn(fd, key, 4) != 4) 582 return -1; 583 if(write(fd, key+12, 4) != 4) 584 return -1; 585 586 /* scramble into two secrets */ 587 sha1(key, sizeof(key), digest, nil); 588 mksecret(fromclientsecret, digest); 589 mksecret(fromserversecret, digest+10); 590 591 /* set up encryption */ 592 i = pushssl(fd, ealgs, fromserversecret, fromclientsecret, nil); 593 if(i < 0) 594 werrstr("can't establish ssl connection: %r"); 595 return i; 596 } 597 598 /* 599 * set authentication mechanism 600 */ 601 int 602 setam(char *name) 603 { 604 for(am = authmethod; am->name != nil; am++) 605 if(strcmp(am->name, name) == 0) 606 return 0; 607 am = authmethod; 608 return -1; 609 } 610 611 /* 612 * set authentication mechanism and encryption/hash algs 613 */ 614 int 615 setamalg(char *s) 616 { 617 ealgs = strchr(s, ' '); 618 if(ealgs != nil) 619 *ealgs++ = 0; 620 return setam(s); 621 } 622 623 char *rmtnotefile = "/mnt/term/dev/cpunote"; 624 625 /* 626 * loop reading /mnt/term/dev/note looking for notes. 627 * The child returns to start the shell. 628 */ 629 void 630 rmtnoteproc(void) 631 { 632 int n, fd, pid, notepid; 633 char buf[256]; 634 635 /* new proc returns to start shell */ 636 pid = rfork(RFPROC|RFFDG|RFNOTEG|RFNAMEG|RFMEM); 637 switch(pid){ 638 case -1: 639 syslog(0, "cpu", "cpu -R: can't start noteproc: %r"); 640 return; 641 case 0: 642 return; 643 } 644 645 /* new proc reads notes from other side and posts them to shell */ 646 switch(notepid = rfork(RFPROC|RFFDG|RFMEM)){ 647 case -1: 648 syslog(0, "cpu", "cpu -R: can't start wait proc: %r"); 649 _exits(0); 650 case 0: 651 fd = open(rmtnotefile, OREAD); 652 if(fd < 0){ 653 syslog(0, "cpu", "cpu -R: can't open %s", rmtnotefile); 654 _exits(0); 655 } 656 657 for(;;){ 658 n = read(fd, buf, sizeof(buf)-1); 659 if(n <= 0){ 660 postnote(PNGROUP, pid, "hangup"); 661 _exits(0); 662 } 663 buf[n] = 0; 664 postnote(PNGROUP, pid, buf); 665 } 666 break; 667 } 668 669 /* original proc waits for shell proc to die and kills note proc */ 670 for(;;){ 671 n = waitpid(); 672 if(n < 0 || n == pid) 673 break; 674 } 675 postnote(PNPROC, notepid, "kill"); 676 _exits(0); 677 } 678 679 enum 680 { 681 Qdir, 682 Qcpunote, 683 684 Nfid = 32, 685 }; 686 687 struct { 688 char *name; 689 Qid qid; 690 ulong perm; 691 } fstab[] = 692 { 693 [Qdir] { ".", {Qdir, 0, QTDIR}, DMDIR|0555 }, 694 [Qcpunote] { "cpunote", {Qcpunote, 0}, 0444 }, 695 }; 696 697 typedef struct Note Note; 698 struct Note 699 { 700 Note *next; 701 char msg[ERRMAX]; 702 }; 703 704 typedef struct Request Request; 705 struct Request 706 { 707 Request *next; 708 Fcall f; 709 }; 710 711 typedef struct Fid Fid; 712 struct Fid 713 { 714 int fid; 715 int file; 716 }; 717 Fid fids[Nfid]; 718 719 struct { 720 Lock; 721 Note *nfirst, *nlast; 722 Request *rfirst, *rlast; 723 } nfs; 724 725 int 726 fsreply(int fd, Fcall *f) 727 { 728 uchar buf[IOHDRSZ+Maxfdata]; 729 int n; 730 731 if(dbg) 732 fprint(2, "<-%F\n", f); 733 n = convS2M(f, buf, sizeof buf); 734 if(n > 0){ 735 if(write(fd, buf, n) != n){ 736 close(fd); 737 return -1; 738 } 739 } 740 return 0; 741 } 742 743 /* match a note read request with a note, reply to the request */ 744 int 745 kick(int fd) 746 { 747 Request *rp; 748 Note *np; 749 int rv; 750 751 for(;;){ 752 lock(&nfs); 753 rp = nfs.rfirst; 754 np = nfs.nfirst; 755 if(rp == nil || np == nil){ 756 unlock(&nfs); 757 break; 758 } 759 nfs.rfirst = rp->next; 760 nfs.nfirst = np->next; 761 unlock(&nfs); 762 763 rp->f.type = Rread; 764 rp->f.count = strlen(np->msg); 765 rp->f.data = np->msg; 766 rv = fsreply(fd, &rp->f); 767 free(rp); 768 free(np); 769 if(rv < 0) 770 return -1; 771 } 772 return 0; 773 } 774 775 void 776 flushreq(int tag) 777 { 778 Request **l, *rp; 779 780 lock(&nfs); 781 for(l = &nfs.rfirst; *l != nil; l = &(*l)->next){ 782 rp = *l; 783 if(rp->f.tag == tag){ 784 *l = rp->next; 785 unlock(&nfs); 786 free(rp); 787 return; 788 } 789 } 790 unlock(&nfs); 791 } 792 793 Fid* 794 getfid(int fid) 795 { 796 int i, freefid; 797 798 freefid = -1; 799 for(i = 0; i < Nfid; i++){ 800 if(freefid < 0 && fids[i].file < 0) 801 freefid = i; 802 if(fids[i].fid == fid) 803 return &fids[i]; 804 } 805 if(freefid >= 0){ 806 fids[freefid].fid = fid; 807 return &fids[freefid]; 808 } 809 return nil; 810 } 811 812 int 813 fsstat(int fd, Fid *fid, Fcall *f) 814 { 815 Dir d; 816 uchar statbuf[256]; 817 818 memset(&d, 0, sizeof(d)); 819 d.name = fstab[fid->file].name; 820 d.uid = user; 821 d.gid = user; 822 d.muid = user; 823 d.qid = fstab[fid->file].qid; 824 d.mode = fstab[fid->file].perm; 825 d.atime = d.mtime = time(0); 826 f->stat = statbuf; 827 f->nstat = convD2M(&d, statbuf, sizeof statbuf); 828 return fsreply(fd, f); 829 } 830 831 int 832 fsread(int fd, Fid *fid, Fcall *f) 833 { 834 Dir d; 835 uchar buf[256]; 836 Request *rp; 837 838 switch(fid->file){ 839 default: 840 return -1; 841 case Qdir: 842 if(f->offset == 0 && f->count >0){ 843 memset(&d, 0, sizeof(d)); 844 d.name = fstab[Qcpunote].name; 845 d.uid = user; 846 d.gid = user; 847 d.muid = user; 848 d.qid = fstab[Qcpunote].qid; 849 d.mode = fstab[Qcpunote].perm; 850 d.atime = d.mtime = time(0); 851 f->count = convD2M(&d, buf, sizeof buf); 852 f->data = (char*)buf; 853 } else 854 f->count = 0; 855 return fsreply(fd, f); 856 case Qcpunote: 857 rp = mallocz(sizeof(*rp), 1); 858 if(rp == nil) 859 return -1; 860 rp->f = *f; 861 lock(&nfs); 862 if(nfs.rfirst == nil) 863 nfs.rfirst = rp; 864 else 865 nfs.rlast->next = rp; 866 nfs.rlast = rp; 867 unlock(&nfs); 868 return kick(fd);; 869 } 870 } 871 872 char Eperm[] = "permission denied"; 873 char Enofile[] = "out of files"; 874 char Enotdir[] = "not a directory"; 875 876 void 877 notefs(int fd) 878 { 879 uchar buf[IOHDRSZ+Maxfdata]; 880 int i, j, n; 881 char err[ERRMAX]; 882 Fcall f; 883 Fid *fid, *nfid; 884 int doreply; 885 886 rfork(RFNOTEG); 887 fmtinstall('F', fcallfmt); 888 889 for(n = 0; n < Nfid; n++) 890 fids[n].file = -1; 891 892 for(;;){ 893 n = read9pmsg(fd, buf, sizeof(buf)); 894 if(n <= 0){ 895 if(dbg) 896 fprint(2, "read9pmsg(%d) returns %d: %r\n", fd, n); 897 break; 898 } 899 if(convM2S(buf, n, &f) < 0) 900 break; 901 if(dbg) 902 fprint(2, "->%F\n", &f); 903 doreply = 1; 904 fid = getfid(f.fid); 905 if(fid == nil){ 906 nofids: 907 f.type = Rerror; 908 f.ename = Enofile; 909 fsreply(fd, &f); 910 continue; 911 } 912 switch(f.type++){ 913 default: 914 f.type = Rerror; 915 f.ename = "unknown type"; 916 break; 917 case Tflush: 918 flushreq(f.oldtag); 919 break; 920 case Tversion: 921 if(f.msize > IOHDRSZ+Maxfdata) 922 f.msize = IOHDRSZ+Maxfdata; 923 break; 924 case Tauth: 925 f.type = Rerror; 926 f.ename = "cpu: authentication not required"; 927 break; 928 case Tattach: 929 f.qid = fstab[Qdir].qid; 930 fid->file = Qdir; 931 break; 932 case Twalk: 933 nfid = nil; 934 if(f.newfid != f.fid){ 935 nfid = getfid(f.newfid); 936 if(nfid == nil) 937 goto nofids; 938 nfid->file = fid->file; 939 fid = nfid; 940 } 941 942 f.ename = nil; 943 for(i=0; i<f.nwname; i++){ 944 if(i > MAXWELEM){ 945 f.type = Rerror; 946 f.ename = "too many name elements"; 947 break; 948 } 949 if(fid->file != Qdir){ 950 f.type = Rerror; 951 f.ename = Enotdir; 952 break; 953 } 954 if(strcmp(f.wname[i], "cpunote") == 0){ 955 fid->file = Qcpunote; 956 f.wqid[i] = fstab[Qcpunote].qid; 957 continue; 958 } 959 f.type = Rerror; 960 f.ename = err; 961 strcpy(err, "cpu: file \""); 962 for(j=0; j<=i; j++){ 963 if(strlen(err)+1+strlen(f.wname[j])+32 > sizeof err) 964 break; 965 if(j != 0) 966 strcat(err, "/"); 967 strcat(err, f.wname[j]); 968 } 969 strcat(err, "\" does not exist"); 970 break; 971 } 972 if(nfid != nil && (f.ename != nil || i < f.nwname)) 973 nfid ->file = -1; 974 if(f.type != Rerror) 975 f.nwqid = i; 976 break; 977 case Topen: 978 if(f.mode != OREAD){ 979 f.type = Rerror; 980 f.ename = Eperm; 981 } 982 f.qid = fstab[fid->file].qid; 983 break; 984 case Tcreate: 985 f.type = Rerror; 986 f.ename = Eperm; 987 break; 988 case Tread: 989 if(fsread(fd, fid, &f) < 0) 990 goto err; 991 doreply = 0; 992 break; 993 case Twrite: 994 f.type = Rerror; 995 f.ename = Eperm; 996 break; 997 case Tclunk: 998 fid->file = -1; 999 break; 1000 case Tremove: 1001 f.type = Rerror; 1002 f.ename = Eperm; 1003 break; 1004 case Tstat: 1005 if(fsstat(fd, fid, &f) < 0) 1006 goto err; 1007 doreply = 0; 1008 break; 1009 case Twstat: 1010 f.type = Rerror; 1011 f.ename = Eperm; 1012 break; 1013 } 1014 if(doreply) 1015 if(fsreply(fd, &f) < 0) 1016 break; 1017 } 1018 err: 1019 if(dbg) 1020 fprint(2, "notefs exiting: %r\n"); 1021 close(fd); 1022 } 1023 1024 char notebuf[ERRMAX]; 1025 1026 void 1027 catcher(void*, char *text) 1028 { 1029 int n; 1030 1031 n = strlen(text); 1032 if(n >= sizeof(notebuf)) 1033 n = sizeof(notebuf)-1; 1034 memmove(notebuf, text, n); 1035 notebuf[n] = '\0'; 1036 noted(NCONT); 1037 } 1038 1039 /* 1040 * mount in /dev a note file for the remote side to read. 1041 */ 1042 void 1043 lclnoteproc(int netfd) 1044 { 1045 int exportfspid; 1046 Waitmsg *w; 1047 Note *np; 1048 int pfd[2]; 1049 1050 if(pipe(pfd) < 0){ 1051 fprint(2, "cpu: can't start note proc: pipe: %r\n"); 1052 return; 1053 } 1054 1055 /* new proc mounts and returns to start exportfs */ 1056 switch(exportfspid = rfork(RFPROC|RFNAMEG|RFFDG|RFMEM)){ 1057 case -1: 1058 fprint(2, "cpu: can't start note proc: rfork: %r\n"); 1059 return; 1060 case 0: 1061 close(pfd[0]); 1062 if(mount(pfd[1], -1, "/dev", MBEFORE, "") < 0) 1063 fprint(2, "cpu: can't mount note proc: %r\n"); 1064 close(pfd[1]); 1065 return; 1066 } 1067 1068 close(netfd); 1069 close(pfd[1]); 1070 1071 /* new proc listens for note file system rpc's */ 1072 switch(rfork(RFPROC|RFNAMEG|RFMEM)){ 1073 case -1: 1074 fprint(2, "cpu: can't start note proc: rfork1: %r\n"); 1075 _exits(0); 1076 case 0: 1077 notefs(pfd[0]); 1078 _exits(0); 1079 } 1080 1081 /* original proc waits for notes */ 1082 notify(catcher); 1083 w = nil; 1084 for(;;) { 1085 *notebuf = 0; 1086 free(w); 1087 w = wait(); 1088 if(w == nil) { 1089 if(*notebuf == 0) 1090 break; 1091 np = mallocz(sizeof(Note), 1); 1092 if(np != nil){ 1093 strcpy(np->msg, notebuf); 1094 lock(&nfs); 1095 if(nfs.nfirst == nil) 1096 nfs.nfirst = np; 1097 else 1098 nfs.nlast->next = np; 1099 nfs.nlast = np; 1100 unlock(&nfs); 1101 kick(pfd[0]); 1102 } 1103 unlock(&nfs); 1104 } else if(w->pid == exportfspid) 1105 break; 1106 } 1107 1108 if(w == nil) 1109 exits(nil); 1110 exits(w->msg); 1111 } 1112