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