con.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923
  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; /* for BSD rlogin authentication */
  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. /* set speed and use fifos if available */
  216. fprint(ctl, "b%d i1", baud);
  217. }
  218. else
  219. fprint(2, "con: cannot open %s: %r\n", cname);
  220. }
  221. if(cmd)
  222. dosystem(net, cmd);
  223. if(!cooked)
  224. rawon();
  225. stdcon(net);
  226. exits(0);
  227. }
  228. /*
  229. * ignore interrupts
  230. */
  231. void
  232. notifyf(void *a, char *msg)
  233. {
  234. USED(a);
  235. if(strstr(msg, "yankee"))
  236. noted(NDFLT);
  237. if(strstr(msg, "closed pipe")
  238. || strcmp(msg, "interrupt") == 0
  239. || strcmp(msg, "hangup") == 0)
  240. noted(NCONT);
  241. noted(NDFLT);
  242. }
  243. /*
  244. * turn keyboard raw mode on
  245. */
  246. void
  247. rawon(void)
  248. {
  249. if(debug)
  250. fprint(2, "rawon\n");
  251. if(raw)
  252. return;
  253. if(consctl < 0)
  254. consctl = open("/dev/consctl", OWRITE);
  255. if(consctl < 0){
  256. // fprint(2, "can't open consctl\n");
  257. return;
  258. }
  259. write(consctl, "rawon", 5);
  260. raw = 1;
  261. }
  262. /*
  263. * turn keyboard raw mode off
  264. */
  265. void
  266. rawoff(void)
  267. {
  268. if(debug)
  269. fprint(2, "rawoff\n");
  270. if(raw == 0)
  271. return;
  272. if(consctl < 0)
  273. consctl = open("/dev/consctl", OWRITE);
  274. if(consctl < 0){
  275. // fprint(2, "can't open consctl\n");
  276. return;
  277. }
  278. write(consctl, "rawoff", 6);
  279. raw = 0;
  280. }
  281. /*
  282. * control menu
  283. */
  284. #define STDHELP "\t(b)reak, (q)uit, (i)nterrupt, toggle printing (r)eturns, (.)continue, (!cmd)\n"
  285. int
  286. menu(int net)
  287. {
  288. char buf[MAXMSG];
  289. long n;
  290. int done;
  291. int wasraw = raw;
  292. if(wasraw)
  293. rawoff();
  294. fprint(2, ">>> ");
  295. for(done = 0; !done; ){
  296. n = read(0, buf, sizeof(buf)-1);
  297. if(n <= 0)
  298. return -1;
  299. buf[n] = 0;
  300. switch(buf[0]){
  301. case '!':
  302. print(buf);
  303. system(net, buf+1);
  304. print("!\n");
  305. done = 1;
  306. break;
  307. case '.':
  308. done = 1;
  309. break;
  310. case 'q':
  311. return -1;
  312. case 'i':
  313. buf[0] = 0x1c;
  314. if(msgfd <= 0)
  315. write(net, buf, 1);
  316. else
  317. sendctl1(msgfd, M_SIGNAL, SIGQUIT);
  318. done = 1;
  319. break;
  320. case 'b':
  321. if(msgfd >= 0)
  322. sendctl(msgfd, M_BREAK);
  323. else if(ctl >= 0)
  324. write(ctl, "k", 1);
  325. done = 1;
  326. break;
  327. case 'r':
  328. returns = 1-returns;
  329. done = 1;
  330. break;
  331. default:
  332. fprint(2, STDHELP);
  333. break;
  334. }
  335. if(!done)
  336. fprint(2, ">>> ");
  337. }
  338. if(wasraw)
  339. rawon();
  340. else
  341. rawoff();
  342. return 0;
  343. }
  344. /*
  345. * the real work. two processes pass bytes back and forth between the
  346. * terminal and the network.
  347. */
  348. void
  349. stdcon(int net)
  350. {
  351. int netpid;
  352. ttypid = getpid();
  353. switch(netpid = rfork(RFMEM|RFPROC)){
  354. case -1:
  355. perror("con");
  356. exits("fork");
  357. case 0:
  358. notify(notifyf);
  359. fromnet(net);
  360. postnote(PNPROC, ttypid, "die yankee dog");
  361. exits(0);
  362. default:
  363. notify(notifyf);
  364. fromkbd(net);
  365. if(notkbd)
  366. for(;;)sleep(0);
  367. postnote(PNPROC, netpid, "die yankee dog");
  368. exits(0);
  369. }
  370. }
  371. /*
  372. * Read the keyboard and write it to the network. '^\' gets us into
  373. * the menu.
  374. */
  375. void
  376. fromkbd(int net)
  377. {
  378. long n;
  379. char buf[MAXMSG];
  380. char *p, *ep;
  381. int eofs;
  382. eofs = 0;
  383. for(;;){
  384. n = read(0, buf, sizeof(buf));
  385. if(n < 0){
  386. if(wasintr()){
  387. if(!raw){
  388. buf[0] = 0x7f;
  389. n = 1;
  390. } else
  391. continue;
  392. } else
  393. return;
  394. }
  395. if(n == 0){
  396. if(++eofs > 32)
  397. return;
  398. } else
  399. eofs = 0;
  400. if(n && memchr(buf, 0x1c, n)){
  401. if(menu(net) < 0)
  402. return;
  403. }else{
  404. if(!raw && n==0){
  405. buf[0] = 0x4;
  406. n = 1;
  407. }
  408. if(nltocr){
  409. ep = buf+n;
  410. for(p = buf; p < ep; p++)
  411. switch(*p){
  412. case '\r':
  413. *p = '\n';
  414. break;
  415. case '\n':
  416. *p = '\r';
  417. break;
  418. }
  419. }
  420. if(iwrite(net, buf, n) != n)
  421. return;
  422. }
  423. }
  424. }
  425. /*
  426. * Read from the network and write to the screen.
  427. * Filter out spurious carriage returns.
  428. */
  429. void
  430. fromnet(int net)
  431. {
  432. long n;
  433. char buf[MAXMSG];
  434. char *cp, *ep;
  435. for(;;){
  436. n = iread(net, buf, sizeof(buf));
  437. if(n < 0)
  438. return;
  439. if(n == 0)
  440. continue;
  441. if (strip)
  442. for (cp=buf; cp<buf+n; cp++)
  443. *cp &= 0177;
  444. if(crtonl) {
  445. /* convert cr's to nl's */
  446. for (cp = buf; cp < buf + n; cp++)
  447. if (*cp == '\r')
  448. *cp = '\n';
  449. }
  450. else if(!returns){
  451. /* convert cr's to null's */
  452. cp = buf;
  453. ep = buf + n;
  454. while(cp < ep && (cp = memchr(cp, '\r', ep-cp))){
  455. memmove(cp, cp+1, ep-cp-1);
  456. ep--;
  457. n--;
  458. }
  459. }
  460. if(n > 0 && iwrite(outfd, buf, n) != n){
  461. if(outfd == 1)
  462. return;
  463. outfd = 1;
  464. if(iwrite(1, buf, n) != n)
  465. return;
  466. }
  467. }
  468. }
  469. /*
  470. * dial and return a data connection
  471. */
  472. int
  473. dodial(char *dest, char *net, char *service)
  474. {
  475. char name[128];
  476. char devdir[128];
  477. int data;
  478. devdir[0] = 0;
  479. strcpy(name, netmkaddr(dest, net, service));
  480. data = dial(name, 0, devdir, &ctl);
  481. if(data < 0){
  482. seterr(name);
  483. return -1;
  484. }
  485. fprint(2, "connected to %s on %s\n", name, devdir);
  486. return data;
  487. }
  488. void
  489. dosystem(int fd, char *cmd)
  490. {
  491. char *p;
  492. p = system(fd, cmd);
  493. if(p){
  494. print("con: %s terminated with %s\n", cmd, p);
  495. exits(p);
  496. }
  497. }
  498. /*
  499. * run a command with the network connection as standard IO
  500. */
  501. char *
  502. system(int fd, char *cmd)
  503. {
  504. int pid;
  505. int p;
  506. static Waitmsg msg;
  507. int pfd[2];
  508. int n;
  509. char buf[4096];
  510. if(pipe(pfd) < 0){
  511. perror("pipe");
  512. return "pipe failed";
  513. }
  514. outfd = pfd[1];
  515. close(consctl);
  516. consctl = -1;
  517. switch(pid = fork()){
  518. case -1:
  519. perror("con");
  520. return "fork failed";
  521. case 0:
  522. close(pfd[1]);
  523. dup(pfd[0], 0);
  524. dup(fd, 1);
  525. close(ctl);
  526. close(fd);
  527. close(pfd[0]);
  528. if(*cmd)
  529. execl("/bin/rc", "rc", "-c", cmd, nil);
  530. else
  531. execl("/bin/rc", "rc", nil);
  532. perror("con");
  533. exits("exec");
  534. break;
  535. default:
  536. close(pfd[0]);
  537. while((n = read(pfd[1], buf, sizeof(buf))) > 0){
  538. if(msgfd >= 0){
  539. if(msgwrite(fd, buf, n) != n)
  540. break;
  541. } else {
  542. if(write(fd, buf, n) != n)
  543. break;
  544. }
  545. }
  546. p = waitpid();
  547. outfd = 1;
  548. close(pfd[1]);
  549. if(p < 0 || p != pid)
  550. return "lost child";
  551. break;
  552. }
  553. return msg.msg;
  554. }
  555. int
  556. wasintr(void)
  557. {
  558. return strcmp(syserr(), "interrupted") == 0;
  559. }
  560. void
  561. punt(char *msg)
  562. {
  563. if(*msg == 0)
  564. msg = transerr;
  565. fprint(2, "con: %s\n", msg);
  566. exits(msg);
  567. }
  568. char*
  569. syserr(void)
  570. {
  571. static char err[ERRMAX];
  572. errstr(err, sizeof err);
  573. return err;
  574. }
  575. void
  576. seterr(char *addr)
  577. {
  578. char *se = syserr();
  579. if(verbose)
  580. fprint(2, "'%s' calling %s\n", se, addr);
  581. if(firsterr[0] && (strstr(se, "translate") ||
  582. strstr(se, "file does not exist") ||
  583. strstr(se, "unknown address") ||
  584. strstr(se, "directory entry not found")))
  585. return;
  586. strcpy(firsterr, se);
  587. }
  588. long
  589. iread(int f, void *a, int n)
  590. {
  591. long m;
  592. for(;;){
  593. m = read(f, a, n);
  594. if(m >= 0 || !wasintr())
  595. break;
  596. }
  597. return m;
  598. }
  599. long
  600. iwrite(int f, void *a, int n)
  601. {
  602. long m;
  603. m = write(f, a, n);
  604. if(m < 0 && wasintr())
  605. return n;
  606. return m;
  607. }
  608. /*
  609. * The rest is to support the V10 mesgld protocol.
  610. */
  611. /*
  612. * network orderings
  613. */
  614. #define get2byte(p) ((p)[0] + ((p)[1]<<8))
  615. #define get4byte(p) ((p)[0] + ((p)[1]<<8) + ((p)[2]<<16) + ((p)[3]<<24))
  616. #define put2byte(p, i) ((p)[0]=(i), (p)[1]=(i)>>8)
  617. #define put4byte(p, i) ((p)[0]=(i), (p)[1]=(i)>>8, (p)[2]=(i)>>16, (p)[3]=(i)>>24)
  618. /*
  619. * tty parameters
  620. */
  621. int sgflags = ECHO;
  622. /*
  623. * a mesgld message
  624. */
  625. struct Msg {
  626. struct mesg h;
  627. char b[MAXMSG];
  628. };
  629. /*
  630. * send an empty mesgld message
  631. */
  632. int
  633. sendctl(int net, int type)
  634. {
  635. Msg m;
  636. m.h.type = type;
  637. m.h.magic = MSGMAGIC;
  638. put2byte(m.h.size, 0);
  639. if(iwrite(net, &m, sizeof(struct mesg)) != sizeof(struct mesg))
  640. return -1;
  641. return 0;
  642. }
  643. /*
  644. * send a one byte mesgld message
  645. */
  646. int
  647. sendctl1(int net, int type, int parm)
  648. {
  649. Msg m;
  650. m.h.type = type;
  651. m.h.magic = MSGMAGIC;
  652. m.b[0] = parm;
  653. put2byte(m.h.size, 1);
  654. if(iwrite(net, &m, sizeof(struct mesg)+1) != sizeof(struct mesg)+1)
  655. return -1;
  656. return 0;
  657. }
  658. /*
  659. * read n bytes. return -1 if it fails, 0 otherwise.
  660. */
  661. int
  662. readupto(int from, char *a, int len)
  663. {
  664. int n;
  665. while(len > 0){
  666. n = iread(from, a, len);
  667. if(n < 0)
  668. return -1;
  669. a += n;
  670. len -= n;
  671. }
  672. return 0;
  673. }
  674. /*
  675. * Decode a mesgld message from the network
  676. */
  677. void
  678. msgfromnet(int net)
  679. {
  680. ulong com;
  681. struct stioctl *io;
  682. struct sgttyb *sg;
  683. struct ttydevb *td;
  684. struct tchars *tc;
  685. int len;
  686. Msg m;
  687. for(;;){
  688. /* get a complete mesgld message */
  689. if(readupto(net, (char*)&m.h, sizeof(struct mesg)) < 0)
  690. break;
  691. if(m.h.magic != MSGMAGIC){
  692. fprint(2, "con: bad message magic 0x%ux\n", m.h.magic);
  693. break;
  694. }
  695. len = get2byte(m.h.size);
  696. if(len > sizeof(m.b)){
  697. len = sizeof(m.b);
  698. fprint(2, "con: mesgld message too long\n");
  699. }
  700. if(len && readupto(net, m.b, len) < 0)
  701. break;
  702. /* decode */
  703. switch(m.h.type){
  704. case M_HANGUP:
  705. if(debug)
  706. fprint(2, "M_HANGUP\n");
  707. return;
  708. case M_DATA:
  709. if(debug)
  710. fprint(2, "M_DATA %d bytes\n", len);
  711. if(iwrite(outfd, m.b, len) != len){
  712. if(outfd == 1)
  713. return;
  714. outfd = 1;
  715. if(iwrite(outfd, m.b, len) != len)
  716. return;
  717. }
  718. continue;
  719. case M_IOCTL:
  720. break;
  721. default:
  722. /* ignore */
  723. if(debug)
  724. fprint(2, "con: unknown message\n");
  725. continue;
  726. }
  727. /*
  728. * answer an ioctl
  729. */
  730. io = (struct stioctl *)m.b;
  731. com = get4byte(io->com);
  732. if(debug)
  733. fprint(2, "M_IOCTL %lud\n", com);
  734. switch(com){
  735. case FIOLOOKLD:
  736. put4byte(io->data, tty_ld);
  737. len = 0;
  738. break;
  739. case TIOCGETP:
  740. sg = (struct sgttyb *)io->data;
  741. sg->sg_ispeed = sg->sg_ospeed = B9600;
  742. sg->sg_erase = 0010; /* back space */
  743. sg->sg_kill = 0025; /* CNTL U */
  744. put2byte(sg->sg_flags, sgflags);
  745. len = sizeof(struct sgttyb);
  746. break;
  747. case TIOCSETN:
  748. case TIOCSETP:
  749. sg = (struct sgttyb *)io->data;
  750. sgflags = get2byte(sg->sg_flags);
  751. if((sgflags&(RAW|CBREAK)) || !(sgflags&ECHO))
  752. rawon();
  753. else
  754. rawoff();
  755. len = 0;
  756. break;
  757. case TIOCGETC:
  758. tc = (struct tchars *)io->data;
  759. tc->t_intrc = 0177;
  760. tc->t_quitc = 0034;
  761. tc->t_startc = 0;
  762. tc->t_stopc = 0;
  763. tc->t_eofc = 0004;
  764. tc->t_brkc = 0;
  765. len = sizeof(struct tchars);
  766. break;
  767. case TIOCSETC:
  768. len = 0;
  769. break;
  770. case TIOCGDEV:
  771. td = (struct ttydevb *)io->data;
  772. td->ispeed = td->ospeed = B9600;
  773. put2byte(td->flags, 0);
  774. len = sizeof(struct ttydevb);
  775. break;
  776. case TIOCSDEV:
  777. len = 0;
  778. break;
  779. default:
  780. /*
  781. * unimplemented
  782. */
  783. m.b[len] = 0;
  784. if(sendctl(net, M_IOCNAK) < 0)
  785. return;
  786. continue;
  787. }
  788. /*
  789. * acknowledge
  790. */
  791. m.h.type = M_IOCACK;
  792. m.h.magic = MSGMAGIC;
  793. len += 4;
  794. put2byte(m.h.size, len);
  795. len += sizeof(struct mesg);
  796. if(iwrite(net, &m, len) != len)
  797. return;
  798. }
  799. }
  800. /*
  801. * Read the keyboard, convert to mesgld messages, and write it to the network.
  802. * '^\' gets us into the menu.
  803. */
  804. void
  805. msgfromkbd(int net)
  806. {
  807. long n;
  808. char buf[MAXMSG];
  809. for(;;){
  810. n = iread(0, buf, sizeof(buf));
  811. if(n < 0)
  812. return;
  813. if(n && memchr(buf, 0034, n)){
  814. if(menu(net) < 0)
  815. return;
  816. } else {
  817. if(msgwrite(net, buf, n) != n)
  818. return;
  819. }
  820. }
  821. }
  822. int
  823. msgwrite(int fd, void *buf, int len)
  824. {
  825. Msg m;
  826. int n;
  827. n = len;
  828. memmove(m.b, buf, n);
  829. put2byte(m.h.size, n);
  830. m.h.magic = MSGMAGIC;
  831. m.h.type = M_DATA;
  832. n += sizeof(struct mesg);
  833. if(iwrite(fd, &m, n) != n)
  834. return -1;
  835. put2byte(m.h.size, 0);
  836. m.h.magic = MSGMAGIC;
  837. m.h.type = M_DELIM;
  838. n = sizeof(struct mesg);
  839. if(iwrite(fd, &m, n) != n)
  840. return -1;
  841. return len;
  842. }