13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier #include <bio.h>
43e12c5d1SDavid du Colombier #include "telnet.h"
53e12c5d1SDavid du Colombier
63e12c5d1SDavid du Colombier int ctl = -1; /* control fd (for break's) */
73e12c5d1SDavid du Colombier int consctl = -1; /* consctl fd */
83e12c5d1SDavid du Colombier
93e12c5d1SDavid du Colombier int ttypid; /* pid's if the 2 processes (used to kill them) */
103e12c5d1SDavid du Colombier int netpid;
113e12c5d1SDavid du Colombier int interrupted;
123e12c5d1SDavid du Colombier int localecho;
13219b2ee8SDavid du Colombier int notkbd;
14219b2ee8SDavid du Colombier
15caf4c6fbSDavid du Colombier static char *srv;
16caf4c6fbSDavid du Colombier
17219b2ee8SDavid du Colombier typedef struct Comm Comm;
18219b2ee8SDavid du Colombier struct Comm {
193e12c5d1SDavid du Colombier int returns;
20219b2ee8SDavid du Colombier int stopped;
21219b2ee8SDavid du Colombier };
22219b2ee8SDavid du Colombier Comm *comm;
233e12c5d1SDavid du Colombier
243e12c5d1SDavid du Colombier int dodial(char*);
253e12c5d1SDavid du Colombier void fromkbd(int);
263e12c5d1SDavid du Colombier void fromnet(int);
27219b2ee8SDavid du Colombier int menu(Biobuf*, int);
28219b2ee8SDavid du Colombier void notifyf(void*, char*);
293e12c5d1SDavid du Colombier void rawoff(void);
303e12c5d1SDavid du Colombier void rawon(void);
313e12c5d1SDavid du Colombier void telnet(int);
323e12c5d1SDavid du Colombier char* system(int, char*);
333e12c5d1SDavid du Colombier int echochange(Biobuf*, int);
343e12c5d1SDavid du Colombier int termsub(Biobuf*, uchar*, int);
353e12c5d1SDavid du Colombier int xlocsub(Biobuf*, uchar*, int);
3674f16c81SDavid du Colombier void* share(ulong);
37219b2ee8SDavid du Colombier
38219b2ee8SDavid du Colombier static int islikeatty(int);
393e12c5d1SDavid du Colombier
403e12c5d1SDavid du Colombier void
usage(void)413e12c5d1SDavid du Colombier usage(void)
423e12c5d1SDavid du Colombier {
43caf4c6fbSDavid du Colombier fatal("usage: telnet [-Cdnr] [-s srv] net!host[!service]", 0, 0);
443e12c5d1SDavid du Colombier }
453e12c5d1SDavid du Colombier
463e12c5d1SDavid du Colombier void
main(int argc,char * argv[])473e12c5d1SDavid du Colombier main(int argc, char *argv[])
483e12c5d1SDavid du Colombier {
49219b2ee8SDavid du Colombier int returns;
50219b2ee8SDavid du Colombier
513e12c5d1SDavid du Colombier returns = 1;
523e12c5d1SDavid du Colombier ARGBEGIN{
533e12c5d1SDavid du Colombier case 'C':
543e12c5d1SDavid du Colombier opt[Echo].noway = 1;
553e12c5d1SDavid du Colombier break;
563e12c5d1SDavid du Colombier case 'd':
573e12c5d1SDavid du Colombier debug = 1;
583e12c5d1SDavid du Colombier break;
59219b2ee8SDavid du Colombier case 'n':
60219b2ee8SDavid du Colombier notkbd = 1;
61219b2ee8SDavid du Colombier break;
623e12c5d1SDavid du Colombier case 'r':
633e12c5d1SDavid du Colombier returns = 0;
643e12c5d1SDavid du Colombier break;
65caf4c6fbSDavid du Colombier case 's':
66caf4c6fbSDavid du Colombier srv = EARGF(usage());
67caf4c6fbSDavid du Colombier break;
683e12c5d1SDavid du Colombier default:
693e12c5d1SDavid du Colombier usage();
703e12c5d1SDavid du Colombier }ARGEND
713e12c5d1SDavid du Colombier
723e12c5d1SDavid du Colombier if(argc != 1)
733e12c5d1SDavid du Colombier usage();
743e12c5d1SDavid du Colombier
753e12c5d1SDavid du Colombier /* options we need routines for */
763e12c5d1SDavid du Colombier opt[Echo].change = echochange;
773e12c5d1SDavid du Colombier opt[Term].sub = termsub;
783e12c5d1SDavid du Colombier opt[Xloc].sub = xlocsub;
793e12c5d1SDavid du Colombier
80219b2ee8SDavid du Colombier comm = share(sizeof(comm));
81219b2ee8SDavid du Colombier comm->returns = returns;
82219b2ee8SDavid du Colombier
833e12c5d1SDavid du Colombier telnet(dodial(argv[0]));
843e12c5d1SDavid du Colombier }
853e12c5d1SDavid du Colombier
863e12c5d1SDavid du Colombier /*
873e12c5d1SDavid du Colombier * dial and return a data connection
883e12c5d1SDavid du Colombier */
893e12c5d1SDavid du Colombier int
dodial(char * dest)903e12c5d1SDavid du Colombier dodial(char *dest)
913e12c5d1SDavid du Colombier {
92c66865c7SDavid du Colombier char *name;
933e12c5d1SDavid du Colombier int data;
94c66865c7SDavid du Colombier char devdir[NETPATHLEN];
953e12c5d1SDavid du Colombier
96c66865c7SDavid du Colombier name = netmkaddr(dest, "tcp", "telnet");
973e12c5d1SDavid du Colombier data = dial(name, 0, devdir, 0);
983e12c5d1SDavid du Colombier if(data < 0)
99bdd62a84SDavid du Colombier fatal("%s: %r", name, 0);
1003e12c5d1SDavid du Colombier fprint(2, "connected to %s on %s\n", name, devdir);
1013e12c5d1SDavid du Colombier return data;
1023e12c5d1SDavid du Colombier }
1033e12c5d1SDavid du Colombier
104caf4c6fbSDavid du Colombier void
post(char * srv,int fd)105caf4c6fbSDavid du Colombier post(char *srv, int fd)
106caf4c6fbSDavid du Colombier {
107caf4c6fbSDavid du Colombier int f;
108caf4c6fbSDavid du Colombier char buf[32];
109caf4c6fbSDavid du Colombier
110caf4c6fbSDavid du Colombier f = create(srv, OWRITE, 0666);
111caf4c6fbSDavid du Colombier if(f < 0)
112caf4c6fbSDavid du Colombier sysfatal("create %s: %r", srv);
113caf4c6fbSDavid du Colombier snprint(buf, sizeof buf, "%d", fd);
114caf4c6fbSDavid du Colombier if(write(f, buf, strlen(buf)) != strlen(buf))
115caf4c6fbSDavid du Colombier sysfatal("write %s: %r", srv);
116caf4c6fbSDavid du Colombier close(f);
117caf4c6fbSDavid du Colombier }
118caf4c6fbSDavid du Colombier
1193e12c5d1SDavid du Colombier /*
1203e12c5d1SDavid du Colombier * two processes pass bytes back and forth between the
1213e12c5d1SDavid du Colombier * terminal and the network.
1223e12c5d1SDavid du Colombier */
1233e12c5d1SDavid du Colombier void
telnet(int net)1243e12c5d1SDavid du Colombier telnet(int net)
1253e12c5d1SDavid du Colombier {
126219b2ee8SDavid du Colombier int pid;
127caf4c6fbSDavid du Colombier int p[2];
128caf4c6fbSDavid du Colombier char *svc;
129219b2ee8SDavid du Colombier
130219b2ee8SDavid du Colombier rawoff();
131caf4c6fbSDavid du Colombier svc = nil;
132caf4c6fbSDavid du Colombier if (srv) {
133caf4c6fbSDavid du Colombier if(pipe(p) < 0)
134caf4c6fbSDavid du Colombier sysfatal("pipe: %r");
135caf4c6fbSDavid du Colombier if (srv[0] != '/')
136caf4c6fbSDavid du Colombier svc = smprint("/srv/%s", srv);
137caf4c6fbSDavid du Colombier else
138caf4c6fbSDavid du Colombier svc = srv;
139caf4c6fbSDavid du Colombier post(svc, p[0]);
140caf4c6fbSDavid du Colombier close(p[0]);
141caf4c6fbSDavid du Colombier dup(p[1], 0);
142caf4c6fbSDavid du Colombier dup(p[1], 1);
143caf4c6fbSDavid du Colombier /* pipe is now std in & out */
144caf4c6fbSDavid du Colombier }
1453e12c5d1SDavid du Colombier ttypid = getpid();
146219b2ee8SDavid du Colombier switch(pid = rfork(RFPROC|RFFDG|RFMEM)){
1473e12c5d1SDavid du Colombier case -1:
1483e12c5d1SDavid du Colombier perror("con");
1493e12c5d1SDavid du Colombier exits("fork");
1503e12c5d1SDavid du Colombier case 0:
1513e12c5d1SDavid du Colombier rawoff();
152219b2ee8SDavid du Colombier notify(notifyf);
1533e12c5d1SDavid du Colombier fromnet(net);
154caf4c6fbSDavid du Colombier if (svc)
155caf4c6fbSDavid du Colombier remove(svc);
1563e12c5d1SDavid du Colombier sendnote(ttypid, "die");
1573e12c5d1SDavid du Colombier exits(0);
1583e12c5d1SDavid du Colombier default:
159219b2ee8SDavid du Colombier netpid = pid;
160219b2ee8SDavid du Colombier notify(notifyf);
1613e12c5d1SDavid du Colombier fromkbd(net);
162219b2ee8SDavid du Colombier if(notkbd)
163caf4c6fbSDavid du Colombier for(;;)
164853458f3SDavid du Colombier sleep(1000); // sleep(0) is a cpuhog
165caf4c6fbSDavid du Colombier if (svc)
166caf4c6fbSDavid du Colombier remove(svc);
1673e12c5d1SDavid du Colombier sendnote(netpid, "die");
1683e12c5d1SDavid du Colombier exits(0);
1693e12c5d1SDavid du Colombier }
1703e12c5d1SDavid du Colombier }
1713e12c5d1SDavid du Colombier
1723e12c5d1SDavid du Colombier /*
1733e12c5d1SDavid du Colombier * Read the keyboard and write it to the network. '^\' gets us into
1743e12c5d1SDavid du Colombier * the menu.
1753e12c5d1SDavid du Colombier */
1763e12c5d1SDavid du Colombier void
fromkbd(int net)1773e12c5d1SDavid du Colombier fromkbd(int net)
1783e12c5d1SDavid du Colombier {
1793e12c5d1SDavid du Colombier Biobuf ib, ob;
180219b2ee8SDavid du Colombier int c, likeatty;
1813e12c5d1SDavid du Colombier int eofs;
1823e12c5d1SDavid du Colombier
1833e12c5d1SDavid du Colombier Binit(&ib, 0, OREAD);
1843e12c5d1SDavid du Colombier Binit(&ob, net, OWRITE);
185219b2ee8SDavid du Colombier
186219b2ee8SDavid du Colombier likeatty = islikeatty(0);
1873e12c5d1SDavid du Colombier eofs = 0;
1883e12c5d1SDavid du Colombier for(;;){
1893e12c5d1SDavid du Colombier c = Bgetc(&ib);
1903e12c5d1SDavid du Colombier
1913e12c5d1SDavid du Colombier /*
1923e12c5d1SDavid du Colombier * with raw off, all ^D's get turned into Eof's.
1933e12c5d1SDavid du Colombier * change them back.
1943e12c5d1SDavid du Colombier * 10 in a row implies that the terminal is really gone so
1953e12c5d1SDavid du Colombier * just hang up.
1963e12c5d1SDavid du Colombier */
1973e12c5d1SDavid du Colombier if(c < 0){
198219b2ee8SDavid du Colombier if(notkbd)
199219b2ee8SDavid du Colombier return;
2003e12c5d1SDavid du Colombier if(eofs++ > 10)
2013e12c5d1SDavid du Colombier return;
2023e12c5d1SDavid du Colombier c = 004;
2033e12c5d1SDavid du Colombier } else
2043e12c5d1SDavid du Colombier eofs = 0;
2053e12c5d1SDavid du Colombier
2063e12c5d1SDavid du Colombier /*
2073e12c5d1SDavid du Colombier * if not in binary mode, look for the ^\ escape to menu.
2083e12c5d1SDavid du Colombier * also turn \n into \r\n
2093e12c5d1SDavid du Colombier */
210219b2ee8SDavid du Colombier if(likeatty || !opt[Binary].local){
2113e12c5d1SDavid du Colombier if(c == 0034){ /* CTRL \ */
2123e12c5d1SDavid du Colombier if(Bflush(&ob) < 0)
2133e12c5d1SDavid du Colombier return;
214219b2ee8SDavid du Colombier if(menu(&ib, net) < 0)
2153e12c5d1SDavid du Colombier return;
2163e12c5d1SDavid du Colombier continue;
2173e12c5d1SDavid du Colombier }
218219b2ee8SDavid du Colombier }
219219b2ee8SDavid du Colombier if(!opt[Binary].local){
220219b2ee8SDavid du Colombier if(c == '\n'){
221219b2ee8SDavid du Colombier /*
222219b2ee8SDavid du Colombier * This is a very strange use of the SGA option.
223219b2ee8SDavid du Colombier * I did this because some systems that don't
224219b2ee8SDavid du Colombier * announce a willingness to supress-go-ahead
225219b2ee8SDavid du Colombier * need the \r\n sequence to recognize input.
226219b2ee8SDavid du Colombier * If someone can explain this to me, please
227219b2ee8SDavid du Colombier * send me mail. - presotto
228219b2ee8SDavid du Colombier */
229219b2ee8SDavid du Colombier if(opt[SGA].remote){
230219b2ee8SDavid du Colombier c = '\r';
231219b2ee8SDavid du Colombier } else {
2323e12c5d1SDavid du Colombier if(Bputc(&ob, '\r') < 0)
2333e12c5d1SDavid du Colombier return;
2343e12c5d1SDavid du Colombier }
235219b2ee8SDavid du Colombier }
236219b2ee8SDavid du Colombier }
2373e12c5d1SDavid du Colombier if(Bputc(&ob, c) < 0)
2383e12c5d1SDavid du Colombier return;
2393e12c5d1SDavid du Colombier if(Bbuffered(&ib) == 0)
2403e12c5d1SDavid du Colombier if(Bflush(&ob) < 0)
2413e12c5d1SDavid du Colombier return;
2423e12c5d1SDavid du Colombier }
2433e12c5d1SDavid du Colombier }
2443e12c5d1SDavid du Colombier
2453e12c5d1SDavid du Colombier /*
2463e12c5d1SDavid du Colombier * Read from the network and write to the screen. If 'stopped' is set
2473e12c5d1SDavid du Colombier * spin and don't read. Filter out spurious carriage returns.
2483e12c5d1SDavid du Colombier */
2493e12c5d1SDavid du Colombier void
fromnet(int net)2503e12c5d1SDavid du Colombier fromnet(int net)
2513e12c5d1SDavid du Colombier {
2523e12c5d1SDavid du Colombier int c;
2537dd7cddfSDavid du Colombier int crnls = 0, freenl = 0, eofs;
2543e12c5d1SDavid du Colombier Biobuf ib, ob;
2553e12c5d1SDavid du Colombier
2563e12c5d1SDavid du Colombier Binit(&ib, net, OREAD);
2573e12c5d1SDavid du Colombier Binit(&ob, 1, OWRITE);
2587dd7cddfSDavid du Colombier eofs = 0;
2597545821fSDavid du Colombier for(;;){
2607545821fSDavid du Colombier if(Bbuffered(&ib) == 0)
2617545821fSDavid du Colombier Bflush(&ob);
2623e12c5d1SDavid du Colombier if(interrupted){
2633e12c5d1SDavid du Colombier interrupted = 0;
2643e12c5d1SDavid du Colombier send2(net, Iac, Interrupt);
2653e12c5d1SDavid du Colombier }
2663e12c5d1SDavid du Colombier c = Bgetc(&ib);
2677dd7cddfSDavid du Colombier if(c < 0){
2687dd7cddfSDavid du Colombier if(eofs++ >= 2)
2693e12c5d1SDavid du Colombier return;
2707dd7cddfSDavid du Colombier continue;
2717dd7cddfSDavid du Colombier }
2727dd7cddfSDavid du Colombier eofs = 0;
2733e12c5d1SDavid du Colombier switch(c){
274219b2ee8SDavid du Colombier case '\n': /* skip nl after string of cr's */
275219b2ee8SDavid du Colombier if(!opt[Binary].local && !comm->returns){
276219b2ee8SDavid du Colombier ++crnls;
277219b2ee8SDavid du Colombier if(freenl == 0)
278219b2ee8SDavid du Colombier break;
279219b2ee8SDavid du Colombier freenl = 0;
2803e12c5d1SDavid du Colombier continue;
2813e12c5d1SDavid du Colombier }
2823e12c5d1SDavid du Colombier break;
283219b2ee8SDavid du Colombier case '\r': /* first cr becomes nl, remainder dropped */
284219b2ee8SDavid du Colombier if(!opt[Binary].local && !comm->returns){
285219b2ee8SDavid du Colombier if(crnls++ == 0){
286219b2ee8SDavid du Colombier freenl = 1;
287219b2ee8SDavid du Colombier c = '\n';
288219b2ee8SDavid du Colombier break;
289219b2ee8SDavid du Colombier }
2903e12c5d1SDavid du Colombier continue;
2913e12c5d1SDavid du Colombier }
292219b2ee8SDavid du Colombier break;
293219b2ee8SDavid du Colombier case 0: /* remove nulls from crnl string */
294219b2ee8SDavid du Colombier if(crnls)
295219b2ee8SDavid du Colombier continue;
2963e12c5d1SDavid du Colombier break;
2973e12c5d1SDavid du Colombier
2983e12c5d1SDavid du Colombier case Iac:
299219b2ee8SDavid du Colombier crnls = 0;
300219b2ee8SDavid du Colombier freenl = 0;
3013e12c5d1SDavid du Colombier c = Bgetc(&ib);
3023e12c5d1SDavid du Colombier if(c == Iac)
3033e12c5d1SDavid du Colombier break;
3043e12c5d1SDavid du Colombier if(Bflush(&ob) < 0)
3053e12c5d1SDavid du Colombier return;
3063e12c5d1SDavid du Colombier if(control(&ib, c) < 0)
3073e12c5d1SDavid du Colombier return;
3083e12c5d1SDavid du Colombier continue;
3093e12c5d1SDavid du Colombier
3103e12c5d1SDavid du Colombier default:
311219b2ee8SDavid du Colombier crnls = 0;
312219b2ee8SDavid du Colombier freenl = 0;
3133e12c5d1SDavid du Colombier break;
3143e12c5d1SDavid du Colombier }
3153e12c5d1SDavid du Colombier if(Bputc(&ob, c) < 0)
3163e12c5d1SDavid du Colombier return;
3173e12c5d1SDavid du Colombier }
3183e12c5d1SDavid du Colombier }
3193e12c5d1SDavid du Colombier
3203e12c5d1SDavid du Colombier /*
3213e12c5d1SDavid du Colombier * turn keyboard raw mode on
3223e12c5d1SDavid du Colombier */
3233e12c5d1SDavid du Colombier void
rawon(void)3243e12c5d1SDavid du Colombier rawon(void)
3253e12c5d1SDavid du Colombier {
3263e12c5d1SDavid du Colombier if(debug)
3273e12c5d1SDavid du Colombier fprint(2, "rawon\n");
3283e12c5d1SDavid du Colombier if(consctl < 0)
3293e12c5d1SDavid du Colombier consctl = open("/dev/consctl", OWRITE);
3303e12c5d1SDavid du Colombier if(consctl < 0){
331*aaee2222SDavid du Colombier fprint(2, "%s: can't open consctl: %r\n", argv0);
3323e12c5d1SDavid du Colombier return;
3333e12c5d1SDavid du Colombier }
3343e12c5d1SDavid du Colombier write(consctl, "rawon", 5);
3353e12c5d1SDavid du Colombier }
3363e12c5d1SDavid du Colombier
3373e12c5d1SDavid du Colombier /*
3383e12c5d1SDavid du Colombier * turn keyboard raw mode off
3393e12c5d1SDavid du Colombier */
3403e12c5d1SDavid du Colombier void
rawoff(void)3413e12c5d1SDavid du Colombier rawoff(void)
3423e12c5d1SDavid du Colombier {
3433e12c5d1SDavid du Colombier if(debug)
3443e12c5d1SDavid du Colombier fprint(2, "rawoff\n");
3453e12c5d1SDavid du Colombier if(consctl < 0)
3463e12c5d1SDavid du Colombier consctl = open("/dev/consctl", OWRITE);
3473e12c5d1SDavid du Colombier if(consctl < 0){
348*aaee2222SDavid du Colombier fprint(2, "%s: can't open consctl: %r\n", argv0);
3493e12c5d1SDavid du Colombier return;
3503e12c5d1SDavid du Colombier }
3513e12c5d1SDavid du Colombier write(consctl, "rawoff", 6);
3523e12c5d1SDavid du Colombier }
3533e12c5d1SDavid du Colombier
3543e12c5d1SDavid du Colombier /*
3553e12c5d1SDavid du Colombier * control menu
3563e12c5d1SDavid du Colombier */
357219b2ee8SDavid du Colombier #define STDHELP "\t(b)reak, (i)nterrupt, (q)uit, (r)eturns, (!cmd), (.)continue\n"
3583e12c5d1SDavid du Colombier
3593e12c5d1SDavid du Colombier int
menu(Biobuf * bp,int net)360219b2ee8SDavid du Colombier menu(Biobuf *bp, int net)
3613e12c5d1SDavid du Colombier {
3623e12c5d1SDavid du Colombier char *cp;
3633e12c5d1SDavid du Colombier int done;
3643e12c5d1SDavid du Colombier
365219b2ee8SDavid du Colombier comm->stopped = 1;
3663e12c5d1SDavid du Colombier
367219b2ee8SDavid du Colombier rawoff();
3683e12c5d1SDavid du Colombier fprint(2, ">>> ");
3693e12c5d1SDavid du Colombier for(done = 0; !done; ){
3703e12c5d1SDavid du Colombier cp = Brdline(bp, '\n');
371219b2ee8SDavid du Colombier if(cp == 0){
372219b2ee8SDavid du Colombier comm->stopped = 0;
3733e12c5d1SDavid du Colombier return -1;
374219b2ee8SDavid du Colombier }
3753e12c5d1SDavid du Colombier cp[Blinelen(bp)-1] = 0;
3763e12c5d1SDavid du Colombier switch(*cp){
3773e12c5d1SDavid du Colombier case '!':
3783e12c5d1SDavid du Colombier system(Bfildes(bp), cp+1);
379219b2ee8SDavid du Colombier done = 1;
3803e12c5d1SDavid du Colombier break;
3813e12c5d1SDavid du Colombier case '.':
3823e12c5d1SDavid du Colombier done = 1;
3833e12c5d1SDavid du Colombier break;
3843e12c5d1SDavid du Colombier case 'q':
385219b2ee8SDavid du Colombier comm->stopped = 0;
3863e12c5d1SDavid du Colombier return -1;
387219b2ee8SDavid du Colombier case 'o':
388219b2ee8SDavid du Colombier switch(*(cp+1)){
389219b2ee8SDavid du Colombier case 'd':
390219b2ee8SDavid du Colombier send3(net, Iac, Do, atoi(cp+2));
391219b2ee8SDavid du Colombier break;
392219b2ee8SDavid du Colombier case 'w':
393219b2ee8SDavid du Colombier send3(net, Iac, Will, atoi(cp+2));
394219b2ee8SDavid du Colombier break;
395219b2ee8SDavid du Colombier }
396219b2ee8SDavid du Colombier break;
397219b2ee8SDavid du Colombier case 'r':
398219b2ee8SDavid du Colombier comm->returns = !comm->returns;
399219b2ee8SDavid du Colombier done = 1;
400219b2ee8SDavid du Colombier break;
4013e12c5d1SDavid du Colombier case 'i':
402219b2ee8SDavid du Colombier send2(net, Iac, Interrupt);
4033e12c5d1SDavid du Colombier break;
4043e12c5d1SDavid du Colombier case 'b':
405219b2ee8SDavid du Colombier send2(net, Iac, Break);
4063e12c5d1SDavid du Colombier break;
4073e12c5d1SDavid du Colombier default:
4083e12c5d1SDavid du Colombier fprint(2, STDHELP);
4093e12c5d1SDavid du Colombier break;
4103e12c5d1SDavid du Colombier }
4113e12c5d1SDavid du Colombier if(!done)
4123e12c5d1SDavid du Colombier fprint(2, ">>> ");
4133e12c5d1SDavid du Colombier }
4143e12c5d1SDavid du Colombier
415219b2ee8SDavid du Colombier rawon();
416219b2ee8SDavid du Colombier comm->stopped = 0;
4173e12c5d1SDavid du Colombier return 0;
4183e12c5d1SDavid du Colombier }
4193e12c5d1SDavid du Colombier
4203e12c5d1SDavid du Colombier /*
4213e12c5d1SDavid du Colombier * ignore interrupts
4223e12c5d1SDavid du Colombier */
423219b2ee8SDavid du Colombier void
notifyf(void * a,char * msg)4243e12c5d1SDavid du Colombier notifyf(void *a, char *msg)
4253e12c5d1SDavid du Colombier {
4263e12c5d1SDavid du Colombier USED(a);
4273e12c5d1SDavid du Colombier if(strcmp(msg, "interrupt") == 0){
4283e12c5d1SDavid du Colombier interrupted = 1;
429219b2ee8SDavid du Colombier noted(NCONT);
4303e12c5d1SDavid du Colombier }
4313e12c5d1SDavid du Colombier if(strcmp(msg, "hangup") == 0)
432219b2ee8SDavid du Colombier noted(NCONT);
433219b2ee8SDavid du Colombier noted(NDFLT);
4343e12c5d1SDavid du Colombier }
4353e12c5d1SDavid du Colombier
4363e12c5d1SDavid du Colombier /*
4373e12c5d1SDavid du Colombier * run a command with the network connection as standard IO
4383e12c5d1SDavid du Colombier */
4393e12c5d1SDavid du Colombier char *
system(int fd,char * cmd)4403e12c5d1SDavid du Colombier system(int fd, char *cmd)
4413e12c5d1SDavid du Colombier {
4423e12c5d1SDavid du Colombier int pid;
4433e12c5d1SDavid du Colombier int p;
4443e12c5d1SDavid du Colombier static Waitmsg msg;
4453e12c5d1SDavid du Colombier
4463e12c5d1SDavid du Colombier if((pid = fork()) == -1){
4473e12c5d1SDavid du Colombier perror("con");
4483e12c5d1SDavid du Colombier return "fork failed";
4493e12c5d1SDavid du Colombier }
4503e12c5d1SDavid du Colombier else if(pid == 0){
4513e12c5d1SDavid du Colombier dup(fd, 0);
4523e12c5d1SDavid du Colombier close(ctl);
4533e12c5d1SDavid du Colombier close(fd);
4543e12c5d1SDavid du Colombier if(*cmd)
455f19e7b74SDavid du Colombier execl("/bin/rc", "rc", "-c", cmd, nil);
4563e12c5d1SDavid du Colombier else
457f19e7b74SDavid du Colombier execl("/bin/rc", "rc", nil);
4583e12c5d1SDavid du Colombier perror("con");
4593e12c5d1SDavid du Colombier exits("exec");
4603e12c5d1SDavid du Colombier }
4619a747e4fSDavid du Colombier for(p = waitpid(); p >= 0; p = waitpid()){
4623e12c5d1SDavid du Colombier if(p == pid)
4633e12c5d1SDavid du Colombier return msg.msg;
4643e12c5d1SDavid du Colombier }
4653e12c5d1SDavid du Colombier return "lost child";
4663e12c5d1SDavid du Colombier }
4673e12c5d1SDavid du Colombier
4683e12c5d1SDavid du Colombier /*
4693e12c5d1SDavid du Colombier * suppress local echo if the remote side is doing it
4703e12c5d1SDavid du Colombier */
4713e12c5d1SDavid du Colombier int
echochange(Biobuf * bp,int cmd)4723e12c5d1SDavid du Colombier echochange(Biobuf *bp, int cmd)
4733e12c5d1SDavid du Colombier {
4743e12c5d1SDavid du Colombier USED(bp);
4753e12c5d1SDavid du Colombier
4763e12c5d1SDavid du Colombier switch(cmd){
4773e12c5d1SDavid du Colombier case Will:
4783e12c5d1SDavid du Colombier rawon();
4793e12c5d1SDavid du Colombier break;
4803e12c5d1SDavid du Colombier case Wont:
4813e12c5d1SDavid du Colombier rawoff();
4823e12c5d1SDavid du Colombier break;
4833e12c5d1SDavid du Colombier }
4843e12c5d1SDavid du Colombier return 0;
4853e12c5d1SDavid du Colombier }
4863e12c5d1SDavid du Colombier
4873e12c5d1SDavid du Colombier /*
4883e12c5d1SDavid du Colombier * send terminal type to the other side
4893e12c5d1SDavid du Colombier */
4903e12c5d1SDavid du Colombier int
termsub(Biobuf * bp,uchar * sub,int n)4913e12c5d1SDavid du Colombier termsub(Biobuf *bp, uchar *sub, int n)
4923e12c5d1SDavid du Colombier {
4933e12c5d1SDavid du Colombier char buf[64];
4943e12c5d1SDavid du Colombier char *term;
4953e12c5d1SDavid du Colombier char *p = buf;
4963e12c5d1SDavid du Colombier
4973e12c5d1SDavid du Colombier if(n < 1)
4983e12c5d1SDavid du Colombier return 0;
4993e12c5d1SDavid du Colombier if(sub[0] == 1){
5003e12c5d1SDavid du Colombier *p++ = Iac;
5013e12c5d1SDavid du Colombier *p++ = Sb;
5023e12c5d1SDavid du Colombier *p++ = opt[Term].code;
5033e12c5d1SDavid du Colombier *p++ = 0;
5043e12c5d1SDavid du Colombier term = getenv("TERM");
5053e12c5d1SDavid du Colombier if(term == 0 || *term == 0)
5063e12c5d1SDavid du Colombier term = "p9win";
507bd389b36SDavid du Colombier strncpy(p, term, sizeof(buf) - (p - buf) - 2);
508bd389b36SDavid du Colombier buf[sizeof(buf)-2] = 0;
509bd389b36SDavid du Colombier p += strlen(p);
5103e12c5d1SDavid du Colombier *p++ = Iac;
5113e12c5d1SDavid du Colombier *p++ = Se;
5123e12c5d1SDavid du Colombier return iwrite(Bfildes(bp), buf, p-buf);
5133e12c5d1SDavid du Colombier }
5143e12c5d1SDavid du Colombier return 0;
5153e12c5d1SDavid du Colombier }
5163e12c5d1SDavid du Colombier
5173e12c5d1SDavid du Colombier /*
5183e12c5d1SDavid du Colombier * send an x display location to the other side
5193e12c5d1SDavid du Colombier */
5203e12c5d1SDavid du Colombier int
xlocsub(Biobuf * bp,uchar * sub,int n)5213e12c5d1SDavid du Colombier xlocsub(Biobuf *bp, uchar *sub, int n)
5223e12c5d1SDavid du Colombier {
5233e12c5d1SDavid du Colombier char buf[64];
5243e12c5d1SDavid du Colombier char *term;
5253e12c5d1SDavid du Colombier char *p = buf;
5263e12c5d1SDavid du Colombier
5273e12c5d1SDavid du Colombier if(n < 1)
5283e12c5d1SDavid du Colombier return 0;
5293e12c5d1SDavid du Colombier if(sub[0] == 1){
5303e12c5d1SDavid du Colombier *p++ = Iac;
5313e12c5d1SDavid du Colombier *p++ = Sb;
5323e12c5d1SDavid du Colombier *p++ = opt[Xloc].code;
5333e12c5d1SDavid du Colombier *p++ = 0;
5343e12c5d1SDavid du Colombier term = getenv("XDISP");
5353e12c5d1SDavid du Colombier if(term == 0 || *term == 0)
5363e12c5d1SDavid du Colombier term = "unknown";
5373e12c5d1SDavid du Colombier strncpy(p, term, p - buf - 2);
5383e12c5d1SDavid du Colombier p += strlen(term);
5393e12c5d1SDavid du Colombier *p++ = Iac;
5403e12c5d1SDavid du Colombier *p++ = Se;
5413e12c5d1SDavid du Colombier return iwrite(Bfildes(bp), buf, p-buf);
5423e12c5d1SDavid du Colombier }
5433e12c5d1SDavid du Colombier return 0;
5443e12c5d1SDavid du Colombier }
545219b2ee8SDavid du Colombier
546219b2ee8SDavid du Colombier static int
islikeatty(int fd)547219b2ee8SDavid du Colombier islikeatty(int fd)
548219b2ee8SDavid du Colombier {
5494f281771SDavid du Colombier char buf[64];
550219b2ee8SDavid du Colombier
5514f281771SDavid du Colombier if(fd2path(fd, buf, sizeof buf) != 0)
552219b2ee8SDavid du Colombier return 0;
5534f281771SDavid du Colombier
5544f281771SDavid du Colombier /* might be /mnt/term/dev/cons */
5554f281771SDavid du Colombier return strlen(buf) >= 9 && strcmp(buf+strlen(buf)-9, "/dev/cons") == 0;
556219b2ee8SDavid du Colombier }
557219b2ee8SDavid du Colombier
558219b2ee8SDavid du Colombier /*
559219b2ee8SDavid du Colombier * create a shared segment. Make is start 2 meg higher than the current
560219b2ee8SDavid du Colombier * end of process memory.
561219b2ee8SDavid du Colombier */
562219b2ee8SDavid du Colombier void*
share(ulong len)56374f16c81SDavid du Colombier share(ulong len)
564219b2ee8SDavid du Colombier {
5657545821fSDavid du Colombier uchar *vastart;
566219b2ee8SDavid du Colombier
5677545821fSDavid du Colombier vastart = sbrk(0);
56874f16c81SDavid du Colombier if(vastart == (void*)-1)
56974f16c81SDavid du Colombier return 0;
5707545821fSDavid du Colombier vastart += 2*1024*1024;
571219b2ee8SDavid du Colombier
57274f16c81SDavid du Colombier if(segattach(0, "shared", vastart, len) == (void*)-1)
573219b2ee8SDavid du Colombier return 0;
574219b2ee8SDavid du Colombier
5757545821fSDavid du Colombier return vastart;
576219b2ee8SDavid du Colombier }
577