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