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