Research V7 development
[unix-history] / usr / src / cmd / cu.c
CommitLineData
30a49333
LM
1#include <stdio.h>
2#include <signal.h>
3#include <sgtty.h>
4/*
5 * cu telno [-t] [-s speed] [-l line] [-a acu]
6 *
7 * -t is for dial-out to terminal.
8 * speeds are: 110, 134, 150, 300, 1200. 300 is default.
9 *
10 * Escape with `~' at beginning of line.
11 * Ordinary diversions are ~<, ~> and ~>>.
12 * Silent output diversions are ~>: and ~>>:.
13 * Terminate output diversion with ~> alone.
14 * Quit is ~. and ~! gives local command or shell.
15 * Also ~$ for canned procedure pumping remote.
16 * ~%put from [to] and ~%take from [to] invoke builtins
17 */
18
19#define CRLF "\r\n"
20#define wrc(ds) write(ds,&c,1)
21
22
23char *devcul = "/dev/cul0";
24char *devcua = "/dev/cua0";
25char *lspeed = "300";
26
27int ln; /* fd for comm line */
28char tkill, terase; /* current input kill & erase */
29char c;
30
31char *connmsg[] = {
32 "",
33 "line busy",
34 "call dropped",
35 "no carrier",
36 "can't fork",
37 "acu access",
38 "tty access",
39 "tty hung",
40 "usage: cu telno [-t] [-s speed] [-l line] [-a acu]"
41};
42
43rdc(ds) {
44
45 ds=read(ds,&c,1);
46 c&= 0177;
47 return (ds);
48}
49
50int intr;
51
52sig2()
53{
54 signal(SIGINT, SIG_IGN);
55 intr = 1;
56}
57
58int set14;
59
60xsleep(n)
61{
62 xalarm(n);
63 pause();
64 xalarm(0);
65}
66
67xalarm(n)
68{
69 set14=n;
70 alarm(n);
71}
72
73sig14()
74{
75 signal(SIGALRM, sig14);
76 if (set14) alarm(1);
77}
78
79int dout;
80int nhup;
81
82/*
83 * main: get connection, set speed for line.
84 * spawn child to invoke rd to read from line, output to fd 1
85 * main line invokes wr to read tty, write to line
86 */
87main(ac,av)
88char *av[];
89{
90 int fk;
91 int speed;
92 char *telno;
93 struct sgttyb stbuf;
94
95 signal(SIGALRM, sig14);
96 if (ac < 2) {
97 prf(connmsg[8]);
98 exit(8);
99 }
100 telno = av[1];
101 av += 2;
102 ac -= 2;
103 for (; ac > 0; av++) {
104 if (equal(*av, "-t")) {
105 dout = 1;
106 --ac;
107 continue;
108 }
109 if (ac < 2)
110 break;
111 if (equal(*av, "-s"))
112 lspeed = *++av;
113 else if (equal(*av, "-l"))
114 devcul = *++av;
115 else if (equal(*av, "-a"))
116 devcua = *++av;
117 else
118 break;
119 ac -= 2;
120 }
121 if (!exists(devcua) || !exists(devcul))
122 exit(9);
123 ln = conn(devcul, devcua, telno);
124 if (ln < 0) {
125 prf("Connect failed: %s",connmsg[-ln]);
126 exit(-ln);
127 }
128 switch(atoi(lspeed)) {
129 case 110:
130 speed = B110;break;
131 case 150:
132 speed = B150;break;
133 default:
134 case 300:
135 speed = B300;break;
136 case 1200:
137 speed = B1200;break;
138 }
139 stbuf.sg_ispeed = speed;
140 stbuf.sg_ospeed = speed;
141 stbuf.sg_flags = EVENP|ODDP;
142 if (!dout)
143 stbuf.sg_flags |= RAW;
144 ioctl(TIOCSETP, ln, &stbuf);
145 ioctl(TIOCEXCL, ln, (struct sgttyb *)NULL);
146 ioctl(TIOCHPCL, ln, (struct sgttyb *)NULL);
147 prf("Connected");
148 if (dout)
149 fk = -1;
150 else
151 fk = fork();
152 nhup = (int)signal(SIGINT, SIG_IGN);
153 if (fk == 0) {
154 rd();
155 prf("\007Lost carrier");
156 exit(3);
157 }
158 mode(1);
159 wr();
160 mode(0);
161 kill(fk, SIGKILL);
162 wait((int *)NULL);
163 stbuf.sg_ispeed = 0;
164 stbuf.sg_ospeed = 0;
165 ioctl(TIOCSETP, ln, &stbuf);
166 prf("Disconnected");
167 exit(0);
168}
169
170/*
171 * conn: establish dial-out connection.
172 * Example: fd = conn("/dev/ttyh","/dev/dn1","4500");
173 * Returns descriptor open to tty for reading and writing.
174 * Negative values (-1...-7) denote errors in connmsg.
175 * Uses alarm and fork/wait; requires sig14 handler.
176 * Be sure to disconnect tty when done, via HUPCL or stty 0.
177 */
178
179conn(dev,acu,telno)
180char *dev, *acu, *telno;
181{
182 struct sgttyb stbuf;
183 extern errno;
184 char *p, *q, b[30];
185 int er, fk, dn, dh, t;
186 er=0;
187 fk=(-1);
188 if ((dn=open(acu,1))<0) {
189 er=(errno == 6? 1:5);
190 goto X;
191 }
192 if ((fk=fork()) == (-1)) {
193 er=4;
194 goto X;
195 }
196 if (fk == 0) {
197 open(dev,2);
198 for (;;) pause();
199 }
200 xsleep(2);
201 /*
202 * copy phone #, assure EON
203 */
204 p=b;
205 q=telno;
206 while (*p++=(*q++))
207 ;
208 p--;
209 if (*(p-1)!='<') {
210 if (*(p-1)!='-') *p++='-';
211 *p++='<';
212 }
213 t=p-b;
214 xalarm(5*t);
215 t=write(dn,b,t);
216 xalarm(0);
217 if (t<0) {
218 er=2;
219 goto X;
220 }
221 /* close(dn) */
222 xalarm(40); /* was 5; sometimes missed carrier */
223 dh = open(dev,2);
224 xalarm(0);
225 if (dh<0) {
226 er=(errno == 4? 3:6);
227 goto X;
228 }
229 ioctl(TIOCGETP, ln, &stbuf);
230 stbuf.sg_flags &= ~ECHO;
231 xalarm(10);
232 ioctl(TIOCSETP, dh, &stbuf);
233 ioctl(TIOCHPCL, dh, (struct sgttyb *)NULL);
234 xalarm(0);
235X:
236 if (er) close(dn);
237 if (fk!=(-1)) {
238 kill(fk, SIGKILL);
239 xalarm(10);
240 while ((t=wait((int *)NULL))!=(-1) && t!=fk);
241 xalarm(0);
242 }
243 return (er? -er:dh);
244}
245
246/*
247 * wr: write to remote: 0 -> line.
248 * ~. terminate
249 * ~<file send file
250 * ~! local login-style shell
251 * ~!cmd execute cmd locally
252 * ~$proc execute proc locally, send output to line
253 * ~%cmd execute builtin cmd (put and take)
254 */
255
256wr()
257{
258 int ds,fk,lcl,x;
259 char *p,b[600];
260 for (;;) {
261 p=b;
262 while (rdc(0) == 1) {
263 if (p == b) lcl=(c == '~');
264 if (p == b+1 && b[0] == '~') lcl=(c!='~');
265 if (c == 0) c=0177;
266 if (!lcl) {
267 if (wrc(ln) == 0) {
268 prf("line gone"); return;
269 }
270 }
271 if (lcl) {
272 if (c == 0177) c=tkill;
273 if (c == '\r' || c == '\n') goto A;
274 if (!dout) wrc(0);
275 }
276 *p++=c;
277 if (c == terase) {
278 p=p-2;
279 if (p<b) p=b;
280 }
281 if (c == tkill || c == 0177 || c == '\r' || c == '\n') p=b;
282 }
283 return;
284A:
285 if (!dout) echo("");
286 *p=0;
287 switch (b[1]) {
288 case '.':
289 case '\004':
290 return;
291 case '!':
292 case '$':
293 fk = fork();
294 if (fk == 0) {
295 close(1);
296 dup(b[1] == '$'? ln:2);
297 close(ln);
298 mode(0);
299 if (!nhup) signal(SIGINT, SIG_DFL);
300 if (b[2] == 0) execl("/bin/sh","-",0);
301 else execl("/bin/sh","sh","-c",b+2,0);
302 prf("Can't execute shell");
303 exit(~0);
304 }
305 if (fk!=(-1)) {
306 while (wait(&x)!=fk);
307 }
308 mode(1);
309 if (b[1] == '!') echo("!");
310 else {
311 if (dout) echo("$");
312 }
313 break;
314 case '<':
315 if (b[2] == 0) break;
316 if ((ds=open(b+2,0))<0) {
317 prf("Can't divert %s",b+1);
318 break;
319 }
320 intr=x=0;
321 mode(2);
322 if (!nhup) signal(SIGINT, sig2);
323 while (!intr && rdc(ds) == 1) {
324 if (wrc(ln) == 0) {
325 x=1;
326 break;
327 }
328 }
329 signal(SIGINT, SIG_IGN);
330 close(ds);
331 mode(1);
332 if (x) return;
333 if (dout) echo("<");
334 break;
335 case '%':
336 dopercen(&b[2]);
337 break;
338 default:
339 prf("Use `~~' to start line with `~'");
340 }
341 continue;
342 }
343}
344
345dopercen(line)
346register char *line;
347{
348 char *args[10];
349 register narg, f;
350 int rcount;
351 for (narg = 0; narg < 10;) {
352 while(*line == ' ' || *line == '\t')
353 line++;
354 if (*line == '\0')
355 break;
356 args[narg++] = line;
357 while(*line != '\0' && *line != ' ' && *line != '\t')
358 line++;
359 if (*line == '\0')
360 break;
361 *line++ = '\0';
362 }
363 if (equal(args[0], "take")) {
364 if (narg < 2) {
365 prf("usage: ~%%take from [to]");
366 return;
367 }
368 if (narg < 3)
369 args[2] = args[1];
370 wrln("echo '~>:'");
371 wrln(args[2]);
372 wrln(";tee /dev/null <");
373 wrln(args[1]);
374 wrln(";echo '~>'\n");
375 return;
376 } else if (equal(args[0], "put")) {
377 if (narg < 2) {
378 prf("usage: ~%%put from [to]");
379 return;
380 }
381 if (narg < 3)
382 args[2] = args[1];
383 if ((f = open(args[1], 0)) < 0) {
384 prf("cannot open: %s", args[1]);
385 return;
386 }
387 wrln("stty -echo;cat >");
388 wrln(args[2]);
389 wrln(";stty echo\n");
390 xsleep(5);
391 intr = 0;
392 if (!nhup)
393 signal(SIGINT, sig2);
394 mode(2);
395 rcount = 0;
396 while(!intr && rdc(f) == 1) {
397 rcount++;
398 if (c == tkill || c == terase)
399 wrln("\\");
400 if (wrc(ln) != 1) {
401 xsleep(2);
402 if (wrc(ln) != 1) {
403 prf("character missed");
404 intr = 1;
405 break;
406 }
407 }
408 }
409 signal(SIGINT, SIG_IGN);
410 close(f);
411 if (intr) {
412 wrln("\n");
413 prf("stopped after %d bytes", rcount);
414 }
415 wrln("\004");
416 xsleep(5);
417 mode(1);
418 return;
419 }
420 prf("~%%%s unknown\n", args[0]);
421}
422
423equal(s1, s2)
424register char *s1, *s2;
425{
426 while (*s1++ == *s2)
427 if (*s2++ == '\0')
428 return(1);
429 return(0);
430}
431
432wrln(s)
433register char *s;
434{
435 while (*s)
436 write(ln, s++, 1);
437}
438
439/*
440 * rd: read from remote: line -> 1
441 * catch:
442 * ~>[>][:][file]
443 * stuff from file...
444 * ~> (ends diversion)
445 */
446
447rd()
448{
449 int ds,slnt;
450 char *p,*q,b[600];
451 p=b;
452 ds=(-1);
453 while (rdc(ln) == 1) {
454 if (ds<0) slnt=0;
455 if (!slnt) wrc(1);
456 *p++=c;
457 if (c!='\n') continue;
458 q=p;
459 p=b;
460 if (b[0]!='~' || b[1]!='>') {
461 if (*(q-2) == '\r') {
462 q--;
463 *(q-1)=(*q);
464 }
465 if (ds>=0) write(ds,b,q-b);
466 continue;
467 }
468 if (ds>=0) close(ds);
469 if (slnt) {
470 write(1, b, q - b);
471 write(1, CRLF, sizeof(CRLF));
472 }
473 if (*(q-2) == '\r') q--;
474 *(q-1)=0;
475 slnt=0;
476 q=b+2;
477 if (*q == '>') q++;
478 if (*q == ':') {
479 slnt=1;
480 q++;
481 }
482 if (*q == 0) {
483 ds=(-1);
484 continue;
485 }
486 if (b[2]!='>' || (ds=open(q,1))<0) ds=creat(q,0644);
487 lseek(ds, (long)0, 2);
488 if (ds<0) prf("Can't divert %s",b+1);
489 }
490}
491
492struct {char lobyte; char hibyte;};
493mode(f)
494{
495 struct sgttyb stbuf;
496 if (dout) return;
497 ioctl(TIOCGETP, 0, &stbuf);
498 tkill = stbuf.sg_kill;
499 terase = stbuf.sg_erase;
500 if (f == 0) {
501 stbuf.sg_flags &= ~RAW;
502 stbuf.sg_flags |= ECHO|CRMOD;
503 }
504 if (f == 1) {
505 stbuf.sg_flags |= RAW;
506 stbuf.sg_flags &= ECHO|CRMOD;
507 }
508 if (f == 2) {
509 stbuf.sg_flags &= ~RAW;
510 stbuf.sg_flags &= ~(ECHO|CRMOD);
511 }
512 ioctl(TIOCSETP, 0, &stbuf);
513}
514
515echo(s)
516char *s;
517{
518 char *p;
519 for (p=s;*p;p++);
520 if (p>s) write(0,s,p-s);
521 write(0,CRLF, sizeof(CRLF));
522}
523
524prf(f, s)
525char *f;
526char *s;
527{
528 fprintf(stderr, f, s);
529 fprintf(stderr, CRLF);
530}
531
532exists(devname)
533char *devname;
534{
535 if (access(devname, 0)==0)
536 return(1);
537 prf("%s does not exist", devname);
538 return(0);
539}