cpu.c 20 KB

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