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