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