Annotation of src/usr.bin/tip/tip.c, Revision 1.49
1.49 ! nicm 1: /* $OpenBSD: tip.c,v 1.48 2010/07/01 21:28:01 nicm Exp $ */
1.5 millert 2: /* $NetBSD: tip.c,v 1.13 1997/04/20 00:03:05 mellon Exp $ */
1.1 deraadt 3:
4: /*
5: * Copyright (c) 1983, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
1.20 millert 16: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: */
32:
33: /*
34: * tip - UNIX link to other systems
35: * tip [-v] [-speed] system-name
36: * or
1.40 nicm 37: * cu phone-number [-s speed] [-l line]
1.1 deraadt 38: */
1.36 nicm 39:
40: #include <sys/types.h>
41: #include <sys/socket.h>
42:
1.49 ! nicm 43: #include <util.h>
! 44:
1.1 deraadt 45: #include "tip.h"
46: #include "pathnames.h"
47:
1.26 moritz 48: static void intprompt(int);
49: static void tipin(void);
50: static int escape(void);
51:
1.8 deraadt 52: int
1.25 deraadt 53: main(int argc, char *argv[])
1.1 deraadt 54: {
1.47 chl 55: char *sys = NULL;
1.36 nicm 56: int i, pair[2];
1.32 mcbride 57:
58: /* XXX preserve previous braindamaged behavior */
1.48 nicm 59: vsetnum(DC, 1);
1.1 deraadt 60:
1.39 nicm 61: if (strcmp(__progname, "cu") == 0) {
1.1 deraadt 62: cumode = 1;
63: cumain(argc, argv);
64: goto cucommon;
65: }
66:
67: if (argc > 4) {
1.34 sobrado 68: fprintf(stderr, "usage: tip [-nv] [-speed] [system-name]\n");
1.1 deraadt 69: exit(1);
70: }
71: if (!isatty(0)) {
1.13 millert 72: fprintf(stderr, "%s: must be interactive\n", __progname);
1.1 deraadt 73: exit(1);
74: }
75:
76: for (; argc > 1; argv++, argc--) {
77: if (argv[1][0] != '-')
1.27 deraadt 78: sys = argv[1];
1.1 deraadt 79: else switch (argv[1][1]) {
80:
81: case 'v':
82: vflag++;
83: break;
84:
1.9 todd 85: case 'n':
86: noesc++;
87: break;
88:
1.1 deraadt 89: case '0': case '1': case '2': case '3': case '4':
90: case '5': case '6': case '7': case '8': case '9':
1.48 nicm 91: vsetnum(BAUDRATE, atoi(&argv[1][1]));
1.1 deraadt 92: break;
93:
94: default:
1.13 millert 95: fprintf(stderr, "%s: %s, unknown option\n", __progname,
96: argv[1]);
1.1 deraadt 97: break;
98: }
99: }
100:
101: (void)signal(SIGINT, cleanup);
102: (void)signal(SIGQUIT, cleanup);
103: (void)signal(SIGHUP, cleanup);
104: (void)signal(SIGTERM, cleanup);
1.24 otto 105: (void)signal(SIGCHLD, SIG_DFL);
1.1 deraadt 106:
1.27 deraadt 107: if ((i = hunt(sys)) == 0) {
1.1 deraadt 108: printf("all ports busy\n");
109: exit(3);
110: }
111: if (i == -1) {
112: printf("link down\n");
113: (void)uu_unlock(uucplock);
114: exit(3);
115: }
116: setbuf(stdout, NULL);
117: loginit();
118: vinit(); /* init variables */
1.12 millert 119: setparity("none"); /* set the parity table */
1.1 deraadt 120:
1.48 nicm 121: if (ttysetup(vgetnum(BAUDRATE))) {
1.49 ! nicm 122: fprintf(stderr, "%s: bad baud rate %d\n", __progname,
1.48 nicm 123: vgetnum(BAUDRATE));
1.19 millert 124: (void)uu_unlock(uucplock);
125: exit(3);
126: }
1.40 nicm 127: con();
1.41 nicm 128:
1.1 deraadt 129: cucommon:
130: /*
131: * From here down the code is shared with
132: * the "cu" version of tip.
133: */
1.10 jason 134:
135: i = fcntl(FD, F_GETFL);
136: if (i == -1) {
137: perror("fcntl");
1.23 deraadt 138: cleanup(0);
1.10 jason 139: }
140: i = fcntl(FD, F_SETFL, i & ~O_NONBLOCK);
141: if (i == -1) {
142: perror("fcntl");
1.23 deraadt 143: cleanup(0);
1.10 jason 144: }
1.1 deraadt 145:
1.2 deraadt 146: tcgetattr(0, &defterm);
1.22 deraadt 147: gotdefterm = 1;
1.2 deraadt 148: term = defterm;
149: term.c_lflag &= ~(ICANON|IEXTEN|ECHO);
150: term.c_iflag &= ~(INPCK|ICRNL);
151: term.c_oflag &= ~OPOST;
152: term.c_cc[VMIN] = 1;
153: term.c_cc[VTIME] = 0;
154: defchars = term;
155: term.c_cc[VINTR] = term.c_cc[VQUIT] = term.c_cc[VSUSP] =
1.25 deraadt 156: term.c_cc[VDSUSP] = term.c_cc[VDISCARD] =
157: term.c_cc[VLNEXT] = _POSIX_VDISABLE;
1.1 deraadt 158: raw();
159:
160: (void)signal(SIGALRM, timeout);
1.29 deraadt 161:
1.48 nicm 162: if (vgetnum(LINEDISC) != TTYDISC) {
163: int ld = (int)vgetnum(LINEDISC);
1.29 deraadt 164: ioctl(FD, TIOCSETD, &ld);
1.48 nicm 165: }
1.1 deraadt 166:
1.36 nicm 167: if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0) {
168: (void)uu_unlock(uucplock);
169: err(3, "socketpair");
170: }
171:
1.1 deraadt 172: /*
173: * Everything's set up now:
174: * connection established (hardwired or dialup)
175: * line conditioned (baud rate, mode, etc.)
176: * internal data structures (variables)
177: * so, fork one process for local side and one for remote.
178: */
179: printf(cumode ? "Connected\r\n" : "\07connected\r\n");
1.23 deraadt 180: tipin_pid = getpid();
1.36 nicm 181: switch (tipout_pid = fork()) {
182: case -1:
183: (void)uu_unlock(uucplock);
184: err(3, "fork");
185: case 0:
186: close(pair[1]);
187: tipin_fd = pair[0];
188: tipout();
189: default:
190: close(pair[0]);
191: tipout_fd = pair[1];
1.1 deraadt 192: tipin();
1.36 nicm 193: }
1.1 deraadt 194: /*NOTREACHED*/
1.8 deraadt 195: exit(0);
1.40 nicm 196: }
197:
198: void
199: con(void)
200: {
1.48 nicm 201: if (vgetstr(CONNECT) != NULL)
202: parwrite(FD, vgetstr(CONNECT), size(vgetstr(CONNECT)));
203: logent(vgetstr(HOST), vgetstr(DEVICE), "call completed");
1.1 deraadt 204: }
205:
206: void
1.23 deraadt 207: cleanup(int signo)
1.1 deraadt 208: {
209: (void)uu_unlock(uucplock);
210: if (odisc)
1.27 deraadt 211: ioctl(0, TIOCSETD, &odisc);
1.22 deraadt 212: unraw();
1.23 deraadt 213: if (signo && tipout_pid) {
214: kill(tipout_pid, signo);
215: wait(NULL);
216: }
1.1 deraadt 217: exit(0);
218: }
219:
220: /*
221: * put the controlling keyboard into raw mode
222: */
1.8 deraadt 223: void
1.25 deraadt 224: raw(void)
1.1 deraadt 225: {
1.2 deraadt 226: tcsetattr(0, TCSADRAIN, &term);
1.1 deraadt 227: }
228:
229:
230: /*
231: * return keyboard to normal mode
232: */
1.8 deraadt 233: void
1.25 deraadt 234: unraw(void)
1.1 deraadt 235: {
1.22 deraadt 236: if (gotdefterm)
237: tcsetattr(0, TCSADRAIN, &defterm);
1.1 deraadt 238: }
239:
240: static jmp_buf promptbuf;
241:
242: /*
243: * Print string ``s'', then read a string
244: * in from the terminal. Handles signals & allows use of
245: * normal erase and kill characters.
246: */
1.8 deraadt 247: int
1.25 deraadt 248: prompt(char *s, char *p, size_t sz)
1.1 deraadt 249: {
1.15 millert 250: int c;
251: char *b = p;
1.1 deraadt 252: sig_t oint, oquit;
253:
254: stoprompt = 0;
255: oint = signal(SIGINT, intprompt);
256: oquit = signal(SIGQUIT, SIG_IGN);
257: unraw();
258: printf("%s", s);
259: if (setjmp(promptbuf) == 0)
1.6 millert 260: while ((c = getchar()) != EOF && (*p = c) != '\n' && --sz > 0)
1.1 deraadt 261: p++;
262: *p = '\0';
263:
264: raw();
265: (void)signal(SIGINT, oint);
266: (void)signal(SIGQUIT, oquit);
267: return (stoprompt || p == b);
268: }
269:
270: /*
271: * Interrupt service routine during prompting
272: */
1.27 deraadt 273: /*ARGSUSED*/
1.26 moritz 274: static void
275: intprompt(int signo)
1.1 deraadt 276: {
277: (void)signal(SIGINT, SIG_IGN);
278: stoprompt = 1;
279: printf("\r\n");
280: longjmp(promptbuf, 1);
281: }
282:
283: /*
284: * ****TIPIN TIPIN****
285: */
1.26 moritz 286: static void
1.25 deraadt 287: tipin(void)
1.1 deraadt 288: {
1.27 deraadt 289: int bol = 1;
1.16 deraadt 290: int gch;
1.17 deraadt 291: char ch;
1.1 deraadt 292:
293: /*
294: * Kinda klugey here...
295: * check for scripting being turned on from the .tiprc file,
296: * but be careful about just using setscript(), as we may
297: * send a SIGEMT before tipout has a chance to set up catching
298: * it; so wait a second, then setscript()
299: */
1.48 nicm 300: if (vgetnum(SCRIPT)) {
1.1 deraadt 301: sleep(1);
302: setscript();
303: }
304:
305: while (1) {
1.2 deraadt 306: gch = getchar()&STRIP_PAR;
1.16 deraadt 307: /* XXX does not check for EOF */
1.48 nicm 308: if (gch == vgetnum(ESCAPE) && bol) {
1.9 todd 309: if (!noesc) {
310: if (!(gch = escape()))
311: continue;
312: }
1.48 nicm 313: } else if (!cumode && gch == vgetnum(RAISECHAR)) {
314: vsetnum(RAISE, !vgetnum(RAISE));
1.1 deraadt 315: continue;
316: } else if (gch == '\r') {
317: bol = 1;
1.17 deraadt 318: ch = gch;
319: parwrite(FD, &ch, 1);
1.48 nicm 320: if (vgetnum(HALFDUPLEX))
1.1 deraadt 321: printf("\r\n");
322: continue;
1.48 nicm 323: } else if (!cumode && gch == vgetnum(FORCE))
324: gch = getchar() & STRIP_PAR;
325: bol = any(gch, vgetstr(EOL));
326: if (vgetnum(RAISE) && islower(gch))
1.1 deraadt 327: gch = toupper(gch);
1.17 deraadt 328: ch = gch;
329: parwrite(FD, &ch, 1);
1.48 nicm 330: if (vgetnum(HALFDUPLEX))
1.17 deraadt 331: printf("%c", ch);
1.1 deraadt 332: }
333: }
334:
335: extern esctable_t etable[];
336:
337: /*
338: * Escape handler --
339: * called on recognition of ``escapec'' at the beginning of a line
340: */
1.26 moritz 341: static int
1.25 deraadt 342: escape(void)
1.1 deraadt 343: {
1.16 deraadt 344: int gch;
1.15 millert 345: esctable_t *p;
1.48 nicm 346: char c = vgetnum(ESCAPE);
1.1 deraadt 347:
1.2 deraadt 348: gch = (getchar()&STRIP_PAR);
1.16 deraadt 349: /* XXX does not check for EOF */
1.1 deraadt 350: for (p = etable; p->e_char; p++)
351: if (p->e_char == gch) {
352: printf("%s", ctrl(c));
353: (*p->e_func)(gch);
354: return (0);
355: }
356: /* ESCAPE ESCAPE forces ESCAPE */
357: if (c != gch)
1.11 deraadt 358: parwrite(FD, &c, 1);
1.1 deraadt 359: return (gch);
360: }
361:
1.8 deraadt 362: int
1.25 deraadt 363: any(int cc, char *p)
1.1 deraadt 364: {
1.8 deraadt 365: char c = cc;
1.1 deraadt 366: while (p && *p)
367: if (*p++ == c)
368: return (1);
369: return (0);
370: }
371:
1.28 deraadt 372: size_t
1.25 deraadt 373: size(char *s)
1.1 deraadt 374: {
1.28 deraadt 375: size_t i = 0;
1.1 deraadt 376:
377: while (s && *s++)
378: i++;
379: return (i);
380: }
381:
382: char *
1.25 deraadt 383: interp(char *s)
1.1 deraadt 384: {
385: static char buf[256];
1.15 millert 386: char *p = buf, c, *q;
1.1 deraadt 387:
1.8 deraadt 388: while ((c = *s++)) {
1.1 deraadt 389: for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++)
390: if (*q++ == c) {
391: *p++ = '\\'; *p++ = *q;
392: goto next;
393: }
394: if (c < 040) {
395: *p++ = '^'; *p++ = c + 'A'-1;
396: } else if (c == 0177) {
397: *p++ = '^'; *p++ = '?';
398: } else
399: *p++ = c;
400: next:
401: ;
402: }
403: *p = '\0';
404: return (buf);
405: }
406:
407: char *
1.25 deraadt 408: ctrl(char c)
1.1 deraadt 409: {
410: static char s[3];
411:
412: if (c < 040 || c == 0177) {
413: s[0] = '^';
414: s[1] = c == 0177 ? '?' : c+'A'-1;
415: s[2] = '\0';
416: } else {
417: s[0] = c;
418: s[1] = '\0';
419: }
420: return (s);
421: }
422:
423: /*
424: * Help command
425: */
1.8 deraadt 426: void
1.26 moritz 427: help(int c)
1.1 deraadt 428: {
1.15 millert 429: esctable_t *p;
1.1 deraadt 430:
431: printf("%c\r\n", c);
432: for (p = etable; p->e_char; p++) {
1.48 nicm 433: printf("%2s", ctrl(vgetnum(ESCAPE)));
1.37 nicm 434: printf("%-2s %s\r\n", ctrl(p->e_char), p->e_help);
1.1 deraadt 435: }
436: }
437:
438: /*
439: * Set up the "remote" tty's state
440: */
1.19 millert 441: int
1.25 deraadt 442: ttysetup(int speed)
1.1 deraadt 443: {
1.2 deraadt 444: struct termios cntrl;
1.1 deraadt 445:
1.19 millert 446: if (tcgetattr(FD, &cntrl))
447: return (-1);
448: cfsetspeed(&cntrl, speed);
1.2 deraadt 449: cntrl.c_cflag &= ~(CSIZE|PARENB);
450: cntrl.c_cflag |= CS8;
1.48 nicm 451: if (vgetnum(DC))
1.5 millert 452: cntrl.c_cflag |= CLOCAL;
1.48 nicm 453: if (vgetnum(HARDWAREFLOW))
1.25 deraadt 454: cntrl.c_cflag |= CRTSCTS;
1.2 deraadt 455: cntrl.c_iflag &= ~(ISTRIP|ICRNL);
456: cntrl.c_oflag &= ~OPOST;
457: cntrl.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO);
458: cntrl.c_cc[VMIN] = 1;
459: cntrl.c_cc[VTIME] = 0;
1.48 nicm 460: if (vgetnum(TAND))
1.2 deraadt 461: cntrl.c_iflag |= IXOFF;
1.19 millert 462: return (tcsetattr(FD, TCSAFLUSH, &cntrl));
1.1 deraadt 463: }
464:
465: static char partab[0200];
466:
467: /*
468: * Do a write to the remote machine with the correct parity.
469: * We are doing 8 bit wide output, so we just generate a character
470: * with the right parity and output it.
471: */
1.8 deraadt 472: void
1.27 deraadt 473: parwrite(int fd, char *buf, size_t n)
1.1 deraadt 474: {
1.15 millert 475: int i;
476: char *bp;
1.1 deraadt 477:
478: bp = buf;
479: if (bits8 == 0)
480: for (i = 0; i < n; i++) {
481: *bp = partab[(*bp) & 0177];
482: bp++;
483: }
484: if (write(fd, buf, n) < 0) {
485: if (errno == EIO)
486: tipabort("Lost carrier.");
487: /* this is questionable */
1.48 nicm 488: abort();;//
1.1 deraadt 489: perror("write");
490: }
491: }
492:
493: /*
494: * Build a parity table with appropriate high-order bit.
495: */
1.8 deraadt 496: void
1.25 deraadt 497: setparity(char *defparity)
1.1 deraadt 498: {
1.15 millert 499: int i, flip, clr, set;
1.1 deraadt 500: char *parity;
1.4 millert 501: extern const unsigned char evenpartab[];
1.1 deraadt 502:
1.48 nicm 503: if (vgetstr(PARITY) == NULL)
504: vsetstr(PARITY, defparity);
505: parity = vgetstr(PARITY);
1.39 nicm 506: if (strcmp(parity, "none") == 0) {
1.1 deraadt 507: bits8 = 1;
508: return;
509: }
510: bits8 = 0;
511: flip = 0;
512: clr = 0377;
513: set = 0;
1.39 nicm 514: if (strcmp(parity, "odd") == 0)
1.1 deraadt 515: flip = 0200; /* reverse bit 7 */
1.39 nicm 516: else if (strcmp(parity, "zero") == 0)
1.1 deraadt 517: clr = 0177; /* turn off bit 7 */
1.39 nicm 518: else if (strcmp(parity, "one") == 0)
1.1 deraadt 519: set = 0200; /* turn on bit 7 */
1.39 nicm 520: else if (strcmp(parity, "even") != 0) {
1.1 deraadt 521: (void) fprintf(stderr, "%s: unknown parity value\r\n", parity);
522: (void) fflush(stderr);
523: }
524: for (i = 0; i < 0200; i++)
1.18 hugh 525: partab[i] = ((evenpartab[i] ^ flip) | set) & clr;
1.1 deraadt 526: }