con.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921
  1. #include <u.h>
  2. #include <libc.h>
  3. #include "rustream.h"
  4. #include "ruttyio.h"
  5. #include "rusignal.h"
  6. #include "rufilio.h"
  7. int debug; /* true if debugging */
  8. int ctl = -1; /* control fd (for break's) */
  9. int raw; /* true if raw is on */
  10. int consctl = -1; /* control fd for cons */
  11. int ttypid; /* pid's if the 2 processes (used to kill them) */
  12. int msgfd = -1; /* mesgld file descriptor (for signals to be written to) */
  13. int outfd = 1; /* local output file descriptor */
  14. int cooked; /* non-zero forces cooked mode */
  15. int returns; /* non-zero forces carriage returns not to be filtered out */
  16. int crtonl; /* non-zero forces carriage returns to be converted to nls coming from net */
  17. int strip; /* strip off parity bits */
  18. char firsterr[2*ERRMAX];
  19. char transerr[2*ERRMAX];
  20. int limited;
  21. char *remuser;
  22. int verbose;
  23. int baud;
  24. int notkbd;
  25. int nltocr; /* translate kbd nl to cr and vice versa */
  26. typedef struct Msg Msg;
  27. #define MAXMSG (2*8192)
  28. int dodial(char*, char*, char*);
  29. void fromkbd(int);
  30. void fromnet(int);
  31. long iread(int, void*, int);
  32. long iwrite(int, void*, int);
  33. int menu(int);
  34. void msgfromkbd(int);
  35. void msgfromnet(int);
  36. int msgwrite(int, void*, int);
  37. void notifyf(void*, char*);
  38. void pass(int, int, int);
  39. void rawoff(void);
  40. void rawon(void);
  41. int readupto(int, char*, int);
  42. int sendctl(int, int);
  43. int sendctl1(int, int, int);
  44. void stdcon(int);
  45. char* system(int, char*);
  46. void dosystem(int, char*);
  47. int wasintr(void);
  48. void punt(char*);
  49. char* syserr(void);
  50. void seterr(char*);
  51. /* protocols */
  52. void device(char*, char*);
  53. void rlogin(char*, char*);
  54. void simple(char*, char*);
  55. void
  56. usage(void)
  57. {
  58. punt("usage: con [-CdnrRsTv] [-b baud] [-l [user]] [-c cmd] net!host[!service]");
  59. }
  60. void
  61. main(int argc, char *argv[])
  62. {
  63. char *dest;
  64. char *cmd = 0;
  65. returns = 1;
  66. ARGBEGIN{
  67. case 'b':
  68. baud = atoi(EARGF(usage()));
  69. break;
  70. case 'd':
  71. debug = 1;
  72. break;
  73. case 'l':
  74. limited = 1;
  75. if(argv[1] != nil && argv[1][0] != '-')
  76. remuser = ARGF();
  77. break;
  78. case 'n':
  79. notkbd = 1;
  80. break;
  81. case 'r':
  82. returns = 0;
  83. break;
  84. case 'R':
  85. nltocr = 1;
  86. break;
  87. case 'T':
  88. crtonl = 1;
  89. break;
  90. case 'C':
  91. cooked = 1;
  92. break;
  93. case 'c':
  94. cmd = ARGF();
  95. break;
  96. case 'v':
  97. verbose = 1;
  98. break;
  99. case 's':
  100. strip = 1;
  101. break;
  102. default:
  103. usage();
  104. }ARGEND
  105. if(argc != 1){
  106. if(remuser == 0)
  107. usage();
  108. dest = remuser;
  109. remuser = 0;
  110. } else
  111. dest = argv[0];
  112. if(*dest == '/' && strchr(dest, '!') == 0)
  113. device(dest, cmd);
  114. else if(limited){
  115. simple(dest, cmd); /* doesn't return if dialout succeeds */
  116. rlogin(dest, cmd); /* doesn't return if dialout succeeds */
  117. } else {
  118. rlogin(dest, cmd); /* doesn't return if dialout succeeds */
  119. simple(dest, cmd); /* doesn't return if dialout succeeds */
  120. }
  121. punt(firsterr);
  122. }
  123. /*
  124. * just dial and use as a byte stream with remote echo
  125. */
  126. void
  127. simple(char *dest, char *cmd)
  128. {
  129. int net;
  130. net = dodial(dest, 0, 0);
  131. if(net < 0)
  132. return;
  133. if(cmd)
  134. dosystem(net, cmd);
  135. if(!cooked)
  136. rawon();
  137. stdcon(net);
  138. exits(0);
  139. }
  140. /*
  141. * dial, do UCB authentication, use as a byte stream with local echo
  142. *
  143. * return if dial failed
  144. */
  145. void
  146. rlogin(char *dest, char *cmd)
  147. {
  148. int net;
  149. char buf[128];
  150. char *p;
  151. char *localuser;
  152. /* only useful on TCP */
  153. if(strchr(dest, '!')
  154. && (strncmp(dest, "tcp!", 4)!=0 && strncmp(dest, "net!", 4)!=0))
  155. return;
  156. net = dodial(dest, "tcp", "login");
  157. if(net < 0)
  158. return;
  159. /*
  160. * do UCB rlogin authentication
  161. */
  162. localuser = getuser();
  163. if(remuser == 0){
  164. if(limited)
  165. remuser = ":";
  166. else
  167. remuser = localuser;
  168. }
  169. p = getenv("TERM");
  170. if(p == 0)
  171. p = "p9";
  172. if(write(net, "", 1)<0
  173. || write(net, localuser, strlen(localuser)+1)<0
  174. || write(net, remuser, strlen(remuser)+1)<0
  175. || write(net, p, strlen(p)+1)<0){
  176. close(net);
  177. punt("BSD authentication failed");
  178. }
  179. if(read(net, buf, 1) != 1)
  180. punt("BSD authentication failed1");
  181. if(buf[0] != 0){
  182. fprint(2, "con: remote error: ");
  183. while(read(net, buf, 1) == 1){
  184. write(2, buf, 1);
  185. if(buf[0] == '\n')
  186. break;
  187. }
  188. exits("read");
  189. }
  190. if(cmd)
  191. dosystem(net, cmd);
  192. if(!cooked)
  193. rawon();
  194. nltocr = 1;
  195. stdcon(net);
  196. exits(0);
  197. }
  198. /*
  199. * just open a device and use it as a connection
  200. */
  201. void
  202. device(char *dest, char *cmd)
  203. {
  204. int net;
  205. char cname[128];
  206. net = open(dest, ORDWR);
  207. if(net < 0) {
  208. fprint(2, "con: cannot open %s: %r\n", dest);
  209. exits("open");
  210. }
  211. snprint(cname, sizeof cname, "%sctl", dest);
  212. ctl = open(cname, ORDWR);
  213. if (baud > 0) {
  214. if(ctl >= 0)
  215. fprint(ctl, "b%d", baud);
  216. else
  217. fprint(2, "con: cannot open %s: %r\n", cname);
  218. }
  219. if(cmd)
  220. dosystem(net, cmd);
  221. if(!cooked)
  222. rawon();
  223. stdcon(net);
  224. exits(0);
  225. }
  226. /*
  227. * ignore interrupts
  228. */
  229. void
  230. notifyf(void *a, char *msg)
  231. {
  232. USED(a);
  233. if(strstr(msg, "yankee"))
  234. noted(NDFLT);
  235. if(strstr(msg, "closed pipe")
  236. || strcmp(msg, "interrupt") == 0
  237. || strcmp(msg, "hangup") == 0)
  238. noted(NCONT);
  239. noted(NDFLT);
  240. }
  241. /*
  242. * turn keyboard raw mode on
  243. */
  244. void
  245. rawon(void)
  246. {
  247. if(debug)
  248. fprint(2, "rawon\n");
  249. if(raw)
  250. return;
  251. if(consctl < 0)
  252. consctl = open("/dev/consctl", OWRITE);
  253. if(consctl < 0){
  254. // fprint(2, "can't open consctl\n");
  255. return;
  256. }
  257. write(consctl, "rawon", 5);
  258. raw = 1;
  259. }
  260. /*
  261. * turn keyboard raw mode off
  262. */
  263. void
  264. rawoff(void)
  265. {
  266. if(debug)
  267. fprint(2, "rawoff\n");
  268. if(raw == 0)
  269. return;
  270. if(consctl < 0)
  271. consctl = open("/dev/consctl", OWRITE);
  272. if(consctl < 0){
  273. // fprint(2, "can't open consctl\n");
  274. return;
  275. }
  276. write(consctl, "rawoff", 6);
  277. raw = 0;
  278. }
  279. /*
  280. * control menu
  281. */
  282. #define STDHELP "\t(b)reak, (q)uit, (i)nterrupt, toggle printing (r)eturns, (.)continue, (!cmd)\n"
  283. int
  284. menu(int net)
  285. {
  286. char buf[MAXMSG];
  287. long n;
  288. int done;
  289. int wasraw = raw;
  290. if(wasraw)
  291. rawoff();
  292. fprint(2, ">>> ");
  293. for(done = 0; !done; ){
  294. n = read(0, buf, sizeof(buf)-1);
  295. if(n <= 0)
  296. return -1;
  297. buf[n] = 0;
  298. switch(buf[0]){
  299. case '!':
  300. print(buf);
  301. system(net, buf+1);
  302. print("!\n");
  303. done = 1;
  304. break;
  305. case '.':
  306. done = 1;
  307. break;
  308. case 'q':
  309. return -1;
  310. case 'i':
  311. buf[0] = 0x1c;
  312. if(msgfd <= 0)
  313. write(net, buf, 1);
  314. else
  315. sendctl1(msgfd, M_SIGNAL, SIGQUIT);
  316. done = 1;
  317. break;
  318. case 'b':
  319. if(msgfd >= 0)
  320. sendctl(msgfd, M_BREAK);
  321. else if(ctl >= 0)
  322. write(ctl, "k", 1);
  323. done = 1;
  324. break;
  325. case 'r':
  326. returns = 1-returns;
  327. done = 1;
  328. break;
  329. default:
  330. fprint(2, STDHELP);
  331. break;
  332. }
  333. if(!done)
  334. fprint(2, ">>> ");
  335. }
  336. if(wasraw)
  337. rawon();
  338. else
  339. rawoff();
  340. return 0;
  341. }
  342. /*
  343. * the real work. two processes pass bytes back and forth between the
  344. * terminal and the network.
  345. */
  346. void
  347. stdcon(int net)
  348. {
  349. int netpid;
  350. ttypid = getpid();
  351. switch(netpid = rfork(RFMEM|RFPROC)){
  352. case -1:
  353. perror("con");
  354. exits("fork");
  355. case 0:
  356. notify(notifyf);
  357. fromnet(net);
  358. postnote(PNPROC, ttypid, "die yankee dog");
  359. exits(0);
  360. default:
  361. notify(notifyf);
  362. fromkbd(net);
  363. if(notkbd)
  364. for(;;)sleep(0);
  365. postnote(PNPROC, netpid, "die yankee dog");
  366. exits(0);
  367. }
  368. }
  369. /*
  370. * Read the keyboard and write it to the network. '^\' gets us into
  371. * the menu.
  372. */
  373. void
  374. fromkbd(int net)
  375. {
  376. long n;
  377. char buf[MAXMSG];
  378. char *p, *ep;
  379. int eofs;
  380. eofs = 0;
  381. for(;;){
  382. n = read(0, buf, sizeof(buf));
  383. if(n < 0){
  384. if(wasintr()){
  385. if(!raw){
  386. buf[0] = 0x7f;
  387. n = 1;
  388. } else
  389. continue;
  390. } else
  391. return;
  392. }
  393. if(n == 0){
  394. if(++eofs > 32)
  395. return;
  396. } else
  397. eofs = 0;
  398. if(n && memchr(buf, 0x1c, n)){
  399. if(menu(net) < 0)
  400. return;
  401. }else{
  402. if(!raw && n==0){
  403. buf[0] = 0x4;
  404. n = 1;
  405. }
  406. if(nltocr){
  407. ep = buf+n;
  408. for(p = buf; p < ep; p++)
  409. switch(*p){
  410. case '\r':
  411. *p = '\n';
  412. break;
  413. case '\n':
  414. *p = '\r';
  415. break;
  416. }
  417. }
  418. if(iwrite(net, buf, n) != n)
  419. return;
  420. }
  421. }
  422. }
  423. /*
  424. * Read from the network and write to the screen.
  425. * Filter out spurious carriage returns.
  426. */
  427. void
  428. fromnet(int net)
  429. {
  430. long n;
  431. char buf[MAXMSG];
  432. char *cp, *ep;
  433. for(;;){
  434. n = iread(net, buf, sizeof(buf));
  435. if(n < 0)
  436. return;
  437. if(n == 0)
  438. continue;
  439. if (strip)
  440. for (cp=buf; cp<buf+n; cp++)
  441. *cp &= 0177;
  442. if(crtonl) {
  443. /* convert cr's to nl's */
  444. for (cp = buf; cp < buf + n; cp++)
  445. if (*cp == '\r')
  446. *cp = '\n';
  447. }
  448. else if(!returns){
  449. /* convert cr's to null's */
  450. cp = buf;
  451. ep = buf + n;
  452. while(cp < ep && (cp = memchr(cp, '\r', ep-cp))){
  453. memmove(cp, cp+1, ep-cp-1);
  454. ep--;
  455. n--;
  456. }
  457. }
  458. if(n > 0 && iwrite(outfd, buf, n) != n){
  459. if(outfd == 1)
  460. return;
  461. outfd = 1;
  462. if(iwrite(1, buf, n) != n)
  463. return;
  464. }
  465. }
  466. }
  467. /*
  468. * dial and return a data connection
  469. */
  470. int
  471. dodial(char *dest, char *net, char *service)
  472. {
  473. char name[128];
  474. char devdir[128];
  475. int data;
  476. devdir[0] = 0;
  477. strcpy(name, netmkaddr(dest, net, service));
  478. data = dial(name, 0, devdir, &ctl);
  479. if(data < 0){
  480. seterr(name);
  481. return -1;
  482. }
  483. fprint(2, "connected to %s on %s\n", name, devdir);
  484. return data;
  485. }
  486. void
  487. dosystem(int fd, char *cmd)
  488. {
  489. char *p;
  490. p = system(fd, cmd);
  491. if(p){
  492. print("con: %s terminated with %s\n", cmd, p);
  493. exits(p);
  494. }
  495. }
  496. /*
  497. * run a command with the network connection as standard IO
  498. */
  499. char *
  500. system(int fd, char *cmd)
  501. {
  502. int pid;
  503. int p;
  504. static Waitmsg msg;
  505. int pfd[2];
  506. int n;
  507. char buf[4096];
  508. if(pipe(pfd) < 0){
  509. perror("pipe");
  510. return "pipe failed";
  511. }
  512. outfd = pfd[1];
  513. close(consctl);
  514. consctl = -1;
  515. switch(pid = fork()){
  516. case -1:
  517. perror("con");
  518. return "fork failed";
  519. case 0:
  520. close(pfd[1]);
  521. dup(pfd[0], 0);
  522. dup(fd, 1);
  523. close(ctl);
  524. close(fd);
  525. close(pfd[0]);
  526. if(*cmd)
  527. execl("/bin/rc", "rc", "-c", cmd, nil);
  528. else
  529. execl("/bin/rc", "rc", nil);
  530. perror("con");
  531. exits("exec");
  532. break;
  533. default:
  534. close(pfd[0]);
  535. while((n = read(pfd[1], buf, sizeof(buf))) > 0){
  536. if(msgfd >= 0){
  537. if(msgwrite(fd, buf, n) != n)
  538. break;
  539. } else {
  540. if(write(fd, buf, n) != n)
  541. break;
  542. }
  543. }
  544. p = waitpid();
  545. outfd = 1;
  546. close(pfd[1]);
  547. if(p < 0 || p != pid)
  548. return "lost child";
  549. break;
  550. }
  551. return msg.msg;
  552. }
  553. int
  554. wasintr(void)
  555. {
  556. return strcmp(syserr(), "interrupted") == 0;
  557. }
  558. void
  559. punt(char *msg)
  560. {
  561. if(*msg == 0)
  562. msg = transerr;
  563. fprint(2, "con: %s\n", msg);
  564. exits(msg);
  565. }
  566. char*
  567. syserr(void)
  568. {
  569. static char err[ERRMAX];
  570. errstr(err, sizeof err);
  571. return err;
  572. }
  573. void
  574. seterr(char *addr)
  575. {
  576. char *se = syserr();
  577. if(verbose)
  578. fprint(2, "'%s' calling %s\n", se, addr);
  579. if(firsterr[0] && (strstr(se, "translate") ||
  580. strstr(se, "file does not exist") ||
  581. strstr(se, "unknown address") ||
  582. strstr(se, "directory entry not found")))
  583. return;
  584. strcpy(firsterr, se);
  585. }
  586. long
  587. iread(int f, void *a, int n)
  588. {
  589. long m;
  590. for(;;){
  591. m = read(f, a, n);
  592. if(m >= 0 || !wasintr())
  593. break;
  594. }
  595. return m;
  596. }
  597. long
  598. iwrite(int f, void *a, int n)
  599. {
  600. long m;
  601. m = write(f, a, n);
  602. if(m < 0 && wasintr())
  603. return n;
  604. return m;
  605. }
  606. /*
  607. * The rest is to support the V10 mesgld protocol.
  608. */
  609. /*
  610. * network orderings
  611. */
  612. #define get2byte(p) ((p)[0] + ((p)[1]<<8))
  613. #define get4byte(p) ((p)[0] + ((p)[1]<<8) + ((p)[2]<<16) + ((p)[3]<<24))
  614. #define put2byte(p, i) ((p)[0]=(i), (p)[1]=(i)>>8)
  615. #define put4byte(p, i) ((p)[0]=(i), (p)[1]=(i)>>8, (p)[2]=(i)>>16, (p)[3]=(i)>>24)
  616. /*
  617. * tty parameters
  618. */
  619. int sgflags = ECHO;
  620. /*
  621. * a mesgld message
  622. */
  623. struct Msg {
  624. struct mesg h;
  625. char b[MAXMSG];
  626. };
  627. /*
  628. * send an empty mesgld message
  629. */
  630. int
  631. sendctl(int net, int type)
  632. {
  633. Msg m;
  634. m.h.type = type;
  635. m.h.magic = MSGMAGIC;
  636. put2byte(m.h.size, 0);
  637. if(iwrite(net, &m, sizeof(struct mesg)) != sizeof(struct mesg))
  638. return -1;
  639. return 0;
  640. }
  641. /*
  642. * send a one byte mesgld message
  643. */
  644. int
  645. sendctl1(int net, int type, int parm)
  646. {
  647. Msg m;
  648. m.h.type = type;
  649. m.h.magic = MSGMAGIC;
  650. m.b[0] = parm;
  651. put2byte(m.h.size, 1);
  652. if(iwrite(net, &m, sizeof(struct mesg)+1) != sizeof(struct mesg)+1)
  653. return -1;
  654. return 0;
  655. }
  656. /*
  657. * read n bytes. return -1 if it fails, 0 otherwise.
  658. */
  659. int
  660. readupto(int from, char *a, int len)
  661. {
  662. int n;
  663. while(len > 0){
  664. n = iread(from, a, len);
  665. if(n < 0)
  666. return -1;
  667. a += n;
  668. len -= n;
  669. }
  670. return 0;
  671. }
  672. /*
  673. * Decode a mesgld message from the network
  674. */
  675. void
  676. msgfromnet(int net)
  677. {
  678. ulong com;
  679. struct stioctl *io;
  680. struct sgttyb *sg;
  681. struct ttydevb *td;
  682. struct tchars *tc;
  683. int len;
  684. Msg m;
  685. for(;;){
  686. /* get a complete mesgld message */
  687. if(readupto(net, (char*)&m.h, sizeof(struct mesg)) < 0)
  688. break;
  689. if(m.h.magic != MSGMAGIC){
  690. fprint(2, "con: bad message magic 0x%ux\n", m.h.magic);
  691. break;
  692. }
  693. len = get2byte(m.h.size);
  694. if(len > sizeof(m.b)){
  695. len = sizeof(m.b);
  696. fprint(2, "con: mesgld message too long\n");
  697. }
  698. if(len && readupto(net, m.b, len) < 0)
  699. break;
  700. /* decode */
  701. switch(m.h.type){
  702. case M_HANGUP:
  703. if(debug)
  704. fprint(2, "M_HANGUP\n");
  705. return;
  706. case M_DATA:
  707. if(debug)
  708. fprint(2, "M_DATA %d bytes\n", len);
  709. if(iwrite(outfd, m.b, len) != len){
  710. if(outfd == 1)
  711. return;
  712. outfd = 1;
  713. if(iwrite(outfd, m.b, len) != len)
  714. return;
  715. }
  716. continue;
  717. case M_IOCTL:
  718. break;
  719. default:
  720. /* ignore */
  721. if(debug)
  722. fprint(2, "con: unknown message\n");
  723. continue;
  724. }
  725. /*
  726. * answer an ioctl
  727. */
  728. io = (struct stioctl *)m.b;
  729. com = get4byte(io->com);
  730. if(debug)
  731. fprint(2, "M_IOCTL %lud\n", com);
  732. switch(com){
  733. case FIOLOOKLD:
  734. put4byte(io->data, tty_ld);
  735. len = 0;
  736. break;
  737. case TIOCGETP:
  738. sg = (struct sgttyb *)io->data;
  739. sg->sg_ispeed = sg->sg_ospeed = B9600;
  740. sg->sg_erase = 0010; /* back space */
  741. sg->sg_kill = 0025; /* CNTL U */
  742. put2byte(sg->sg_flags, sgflags);
  743. len = sizeof(struct sgttyb);
  744. break;
  745. case TIOCSETN:
  746. case TIOCSETP:
  747. sg = (struct sgttyb *)io->data;
  748. sgflags = get2byte(sg->sg_flags);
  749. if((sgflags&(RAW|CBREAK)) || !(sgflags&ECHO))
  750. rawon();
  751. else
  752. rawoff();
  753. len = 0;
  754. break;
  755. case TIOCGETC:
  756. tc = (struct tchars *)io->data;
  757. tc->t_intrc = 0177;
  758. tc->t_quitc = 0034;
  759. tc->t_startc = 0;
  760. tc->t_stopc = 0;
  761. tc->t_eofc = 0004;
  762. tc->t_brkc = 0;
  763. len = sizeof(struct tchars);
  764. break;
  765. case TIOCSETC:
  766. len = 0;
  767. break;
  768. case TIOCGDEV:
  769. td = (struct ttydevb *)io->data;
  770. td->ispeed = td->ospeed = B9600;
  771. put2byte(td->flags, 0);
  772. len = sizeof(struct ttydevb);
  773. break;
  774. case TIOCSDEV:
  775. len = 0;
  776. break;
  777. default:
  778. /*
  779. * unimplemented
  780. */
  781. m.b[len] = 0;
  782. if(sendctl(net, M_IOCNAK) < 0)
  783. return;
  784. continue;
  785. }
  786. /*
  787. * acknowledge
  788. */
  789. m.h.type = M_IOCACK;
  790. m.h.magic = MSGMAGIC;
  791. len += 4;
  792. put2byte(m.h.size, len);
  793. len += sizeof(struct mesg);
  794. if(iwrite(net, &m, len) != len)
  795. return;
  796. }
  797. }
  798. /*
  799. * Read the keyboard, convert to mesgld messages, and write it to the network.
  800. * '^\' gets us into the menu.
  801. */
  802. void
  803. msgfromkbd(int net)
  804. {
  805. long n;
  806. char buf[MAXMSG];
  807. for(;;){
  808. n = iread(0, buf, sizeof(buf));
  809. if(n < 0)
  810. return;
  811. if(n && memchr(buf, 0034, n)){
  812. if(menu(net) < 0)
  813. return;
  814. } else {
  815. if(msgwrite(net, buf, n) != n)
  816. return;
  817. }
  818. }
  819. }
  820. int
  821. msgwrite(int fd, void *buf, int len)
  822. {
  823. Msg m;
  824. int n;
  825. n = len;
  826. memmove(m.b, buf, n);
  827. put2byte(m.h.size, n);
  828. m.h.magic = MSGMAGIC;
  829. m.h.type = M_DATA;
  830. n += sizeof(struct mesg);
  831. if(iwrite(fd, &m, n) != n)
  832. return -1;
  833. put2byte(m.h.size, 0);
  834. m.h.magic = MSGMAGIC;
  835. m.h.type = M_DELIM;
  836. n = sizeof(struct mesg);
  837. if(iwrite(fd, &m, n) != n)
  838. return -1;
  839. return len;
  840. }