Annotation of src/usr.bin/tip/tip.c, Revision 1.44
1.44 ! nicm 1: /* $OpenBSD: tip.c,v 1.43 2010/06/29 23:10:56 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.1 deraadt 43: #include "tip.h"
44: #include "pathnames.h"
45:
1.2 deraadt 46: int disc = TTYDISC; /* tip normally runs this way */
1.1 deraadt 47: char PNbuf[256]; /* This limits the size of a number */
48:
1.26 moritz 49: static void intprompt(int);
50: static void tipin(void);
51: static int escape(void);
52:
1.8 deraadt 53: int
1.25 deraadt 54: main(int argc, char *argv[])
1.1 deraadt 55: {
1.33 moritz 56: char *sys = NULL, sbuf[12], *p;
1.36 nicm 57: int i, pair[2];
1.32 mcbride 58:
59: /* XXX preserve previous braindamaged behavior */
1.42 nicm 60: setboolean(value(DC), 1);
1.1 deraadt 61:
1.39 nicm 62: if (strcmp(__progname, "cu") == 0) {
1.1 deraadt 63: cumode = 1;
64: cumain(argc, argv);
65: goto cucommon;
66: }
67:
68: if (argc > 4) {
1.34 sobrado 69: fprintf(stderr, "usage: tip [-nv] [-speed] [system-name]\n");
1.1 deraadt 70: exit(1);
71: }
72: if (!isatty(0)) {
1.13 millert 73: fprintf(stderr, "%s: must be interactive\n", __progname);
1.1 deraadt 74: exit(1);
75: }
76:
77: for (; argc > 1; argv++, argc--) {
78: if (argv[1][0] != '-')
1.27 deraadt 79: sys = argv[1];
1.1 deraadt 80: else switch (argv[1][1]) {
81:
82: case 'v':
83: vflag++;
84: break;
85:
1.9 todd 86: case 'n':
87: noesc++;
88: break;
89:
1.1 deraadt 90: case '0': case '1': case '2': case '3': case '4':
91: case '5': case '6': case '7': case '8': case '9':
1.43 nicm 92: setnumber(value(BAUDRATE), atoi(&argv[1][1]));
1.1 deraadt 93: break;
94:
95: default:
1.13 millert 96: fprintf(stderr, "%s: %s, unknown option\n", __progname,
97: argv[1]);
1.1 deraadt 98: break;
99: }
100: }
101:
102: (void)signal(SIGINT, cleanup);
103: (void)signal(SIGQUIT, cleanup);
104: (void)signal(SIGHUP, cleanup);
105: (void)signal(SIGTERM, cleanup);
1.24 otto 106: (void)signal(SIGCHLD, SIG_DFL);
1.1 deraadt 107:
1.27 deraadt 108: if ((i = hunt(sys)) == 0) {
1.1 deraadt 109: printf("all ports busy\n");
110: exit(3);
111: }
112: if (i == -1) {
113: printf("link down\n");
114: (void)uu_unlock(uucplock);
115: exit(3);
116: }
117: setbuf(stdout, NULL);
118: loginit();
119: vinit(); /* init variables */
1.12 millert 120: setparity("none"); /* set the parity table */
1.1 deraadt 121:
1.41 nicm 122: if (ttysetup(number(value(BAUDRATE)))) {
1.19 millert 123: fprintf(stderr, "%s: bad baud rate %ld\n", __progname,
124: number(value(BAUDRATE)));
125: (void)uu_unlock(uucplock);
126: exit(3);
127: }
1.40 nicm 128: con();
1.41 nicm 129:
1.1 deraadt 130: cucommon:
131: /*
132: * From here down the code is shared with
133: * the "cu" version of tip.
134: */
1.10 jason 135:
136: i = fcntl(FD, F_GETFL);
137: if (i == -1) {
138: perror("fcntl");
1.23 deraadt 139: cleanup(0);
1.10 jason 140: }
141: i = fcntl(FD, F_SETFL, i & ~O_NONBLOCK);
142: if (i == -1) {
143: perror("fcntl");
1.23 deraadt 144: cleanup(0);
1.10 jason 145: }
1.1 deraadt 146:
1.2 deraadt 147: tcgetattr(0, &defterm);
1.22 deraadt 148: gotdefterm = 1;
1.2 deraadt 149: term = defterm;
150: term.c_lflag &= ~(ICANON|IEXTEN|ECHO);
151: term.c_iflag &= ~(INPCK|ICRNL);
152: term.c_oflag &= ~OPOST;
153: term.c_cc[VMIN] = 1;
154: term.c_cc[VTIME] = 0;
155: defchars = term;
156: term.c_cc[VINTR] = term.c_cc[VQUIT] = term.c_cc[VSUSP] =
1.25 deraadt 157: term.c_cc[VDSUSP] = term.c_cc[VDISCARD] =
158: term.c_cc[VLNEXT] = _POSIX_VDISABLE;
1.1 deraadt 159: raw();
160:
161: (void)signal(SIGALRM, timeout);
1.29 deraadt 162:
163: if (value(LINEDISC) != TTYDISC) {
164: int ld = (int)value(LINEDISC);
165: ioctl(FD, TIOCSETD, &ld);
166: }
1.1 deraadt 167:
1.36 nicm 168: if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0) {
169: (void)uu_unlock(uucplock);
170: err(3, "socketpair");
171: }
172:
1.1 deraadt 173: /*
174: * Everything's set up now:
175: * connection established (hardwired or dialup)
176: * line conditioned (baud rate, mode, etc.)
177: * internal data structures (variables)
178: * so, fork one process for local side and one for remote.
179: */
180: printf(cumode ? "Connected\r\n" : "\07connected\r\n");
1.23 deraadt 181: tipin_pid = getpid();
1.36 nicm 182: switch (tipout_pid = fork()) {
183: case -1:
184: (void)uu_unlock(uucplock);
185: err(3, "fork");
186: case 0:
187: close(pair[1]);
188: tipin_fd = pair[0];
189: tipout();
190: default:
191: close(pair[0]);
192: tipout_fd = pair[1];
1.1 deraadt 193: tipin();
1.36 nicm 194: }
1.1 deraadt 195: /*NOTREACHED*/
1.8 deraadt 196: exit(0);
1.40 nicm 197: }
198:
199: void
200: con(void)
201: {
202: if (CM != NULL)
203: parwrite(FD, CM, size(CM));
204: logent(value(HOST), DV, "call completed");
1.1 deraadt 205: }
206:
207: void
1.23 deraadt 208: cleanup(int signo)
1.1 deraadt 209: {
210: (void)uu_unlock(uucplock);
211: if (odisc)
1.27 deraadt 212: ioctl(0, TIOCSETD, &odisc);
1.22 deraadt 213: unraw();
1.23 deraadt 214: if (signo && tipout_pid) {
215: kill(tipout_pid, signo);
216: wait(NULL);
217: }
1.1 deraadt 218: exit(0);
219: }
220:
221: /*
222: * put the controlling keyboard into raw mode
223: */
1.8 deraadt 224: void
1.25 deraadt 225: raw(void)
1.1 deraadt 226: {
1.2 deraadt 227: tcsetattr(0, TCSADRAIN, &term);
1.1 deraadt 228: }
229:
230:
231: /*
232: * return keyboard to normal mode
233: */
1.8 deraadt 234: void
1.25 deraadt 235: unraw(void)
1.1 deraadt 236: {
1.22 deraadt 237: if (gotdefterm)
238: tcsetattr(0, TCSADRAIN, &defterm);
1.1 deraadt 239: }
240:
241: static jmp_buf promptbuf;
242:
243: /*
244: * Print string ``s'', then read a string
245: * in from the terminal. Handles signals & allows use of
246: * normal erase and kill characters.
247: */
1.8 deraadt 248: int
1.25 deraadt 249: prompt(char *s, char *p, size_t sz)
1.1 deraadt 250: {
1.15 millert 251: int c;
252: char *b = p;
1.1 deraadt 253: sig_t oint, oquit;
254:
255: stoprompt = 0;
256: oint = signal(SIGINT, intprompt);
257: oquit = signal(SIGQUIT, SIG_IGN);
258: unraw();
259: printf("%s", s);
260: if (setjmp(promptbuf) == 0)
1.6 millert 261: while ((c = getchar()) != EOF && (*p = c) != '\n' && --sz > 0)
1.1 deraadt 262: p++;
263: *p = '\0';
264:
265: raw();
266: (void)signal(SIGINT, oint);
267: (void)signal(SIGQUIT, oquit);
268: return (stoprompt || p == b);
269: }
270:
271: /*
272: * Interrupt service routine during prompting
273: */
1.27 deraadt 274: /*ARGSUSED*/
1.26 moritz 275: static void
276: intprompt(int signo)
1.1 deraadt 277: {
278: (void)signal(SIGINT, SIG_IGN);
279: stoprompt = 1;
280: printf("\r\n");
281: longjmp(promptbuf, 1);
282: }
283:
284: /*
285: * ****TIPIN TIPIN****
286: */
1.26 moritz 287: static void
1.25 deraadt 288: tipin(void)
1.1 deraadt 289: {
1.27 deraadt 290: int bol = 1;
1.16 deraadt 291: int gch;
1.17 deraadt 292: char ch;
1.1 deraadt 293:
294: /*
295: * Kinda klugey here...
296: * check for scripting being turned on from the .tiprc file,
297: * but be careful about just using setscript(), as we may
298: * send a SIGEMT before tipout has a chance to set up catching
299: * it; so wait a second, then setscript()
300: */
301: if (boolean(value(SCRIPT))) {
302: sleep(1);
303: setscript();
304: }
305:
306: while (1) {
1.2 deraadt 307: gch = getchar()&STRIP_PAR;
1.16 deraadt 308: /* XXX does not check for EOF */
1.1 deraadt 309: if ((gch == character(value(ESCAPE))) && bol) {
1.9 todd 310: if (!noesc) {
311: if (!(gch = escape()))
312: continue;
313: }
1.1 deraadt 314: } else if (!cumode && gch == character(value(RAISECHAR))) {
1.4 millert 315: setboolean(value(RAISE), !boolean(value(RAISE)));
1.1 deraadt 316: continue;
317: } else if (gch == '\r') {
318: bol = 1;
1.17 deraadt 319: ch = gch;
320: parwrite(FD, &ch, 1);
1.1 deraadt 321: if (boolean(value(HALFDUPLEX)))
322: printf("\r\n");
323: continue;
324: } else if (!cumode && gch == character(value(FORCE)))
1.2 deraadt 325: gch = getchar()&STRIP_PAR;
1.1 deraadt 326: bol = any(gch, value(EOL));
327: if (boolean(value(RAISE)) && islower(gch))
328: gch = toupper(gch);
1.17 deraadt 329: ch = gch;
330: parwrite(FD, &ch, 1);
1.1 deraadt 331: if (boolean(value(HALFDUPLEX)))
1.17 deraadt 332: printf("%c", ch);
1.1 deraadt 333: }
334: }
335:
336: extern esctable_t etable[];
337:
338: /*
339: * Escape handler --
340: * called on recognition of ``escapec'' at the beginning of a line
341: */
1.26 moritz 342: static int
1.25 deraadt 343: escape(void)
1.1 deraadt 344: {
1.16 deraadt 345: int gch;
1.15 millert 346: esctable_t *p;
1.1 deraadt 347: char c = character(value(ESCAPE));
348:
1.2 deraadt 349: gch = (getchar()&STRIP_PAR);
1.16 deraadt 350: /* XXX does not check for EOF */
1.1 deraadt 351: for (p = etable; p->e_char; p++)
352: if (p->e_char == gch) {
353: printf("%s", ctrl(c));
354: (*p->e_func)(gch);
355: return (0);
356: }
357: /* ESCAPE ESCAPE forces ESCAPE */
358: if (c != gch)
1.11 deraadt 359: parwrite(FD, &c, 1);
1.1 deraadt 360: return (gch);
361: }
362:
1.8 deraadt 363: int
1.25 deraadt 364: any(int cc, char *p)
1.1 deraadt 365: {
1.8 deraadt 366: char c = cc;
1.1 deraadt 367: while (p && *p)
368: if (*p++ == c)
369: return (1);
370: return (0);
371: }
372:
1.28 deraadt 373: size_t
1.25 deraadt 374: size(char *s)
1.1 deraadt 375: {
1.28 deraadt 376: size_t i = 0;
1.1 deraadt 377:
378: while (s && *s++)
379: i++;
380: return (i);
381: }
382:
383: char *
1.25 deraadt 384: interp(char *s)
1.1 deraadt 385: {
386: static char buf[256];
1.15 millert 387: char *p = buf, c, *q;
1.1 deraadt 388:
1.8 deraadt 389: while ((c = *s++)) {
1.1 deraadt 390: for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++)
391: if (*q++ == c) {
392: *p++ = '\\'; *p++ = *q;
393: goto next;
394: }
395: if (c < 040) {
396: *p++ = '^'; *p++ = c + 'A'-1;
397: } else if (c == 0177) {
398: *p++ = '^'; *p++ = '?';
399: } else
400: *p++ = c;
401: next:
402: ;
403: }
404: *p = '\0';
405: return (buf);
406: }
407:
408: char *
1.25 deraadt 409: ctrl(char c)
1.1 deraadt 410: {
411: static char s[3];
412:
413: if (c < 040 || c == 0177) {
414: s[0] = '^';
415: s[1] = c == 0177 ? '?' : c+'A'-1;
416: s[2] = '\0';
417: } else {
418: s[0] = c;
419: s[1] = '\0';
420: }
421: return (s);
422: }
423:
424: /*
425: * Help command
426: */
1.8 deraadt 427: void
1.26 moritz 428: help(int c)
1.1 deraadt 429: {
1.15 millert 430: esctable_t *p;
1.1 deraadt 431:
432: printf("%c\r\n", c);
433: for (p = etable; p->e_char; p++) {
434: printf("%2s", ctrl(character(value(ESCAPE))));
1.37 nicm 435: printf("%-2s %s\r\n", ctrl(p->e_char), p->e_help);
1.1 deraadt 436: }
437: }
438:
439: /*
440: * Set up the "remote" tty's state
441: */
1.19 millert 442: int
1.25 deraadt 443: ttysetup(int speed)
1.1 deraadt 444: {
1.2 deraadt 445: struct termios cntrl;
1.1 deraadt 446:
1.19 millert 447: if (tcgetattr(FD, &cntrl))
448: return (-1);
449: cfsetspeed(&cntrl, speed);
1.2 deraadt 450: cntrl.c_cflag &= ~(CSIZE|PARENB);
451: cntrl.c_cflag |= CS8;
1.5 millert 452: if (boolean(value(DC)))
453: cntrl.c_cflag |= CLOCAL;
1.21 millert 454: if (boolean(value(HARDWAREFLOW)))
1.25 deraadt 455: cntrl.c_cflag |= CRTSCTS;
1.2 deraadt 456: cntrl.c_iflag &= ~(ISTRIP|ICRNL);
457: cntrl.c_oflag &= ~OPOST;
458: cntrl.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO);
459: cntrl.c_cc[VMIN] = 1;
460: cntrl.c_cc[VTIME] = 0;
1.1 deraadt 461: if (boolean(value(TAND)))
1.2 deraadt 462: cntrl.c_iflag |= IXOFF;
1.19 millert 463: return (tcsetattr(FD, TCSAFLUSH, &cntrl));
1.1 deraadt 464: }
465:
466: static char partab[0200];
467:
468: /*
469: * Do a write to the remote machine with the correct parity.
470: * We are doing 8 bit wide output, so we just generate a character
471: * with the right parity and output it.
472: */
1.8 deraadt 473: void
1.27 deraadt 474: parwrite(int fd, char *buf, size_t n)
1.1 deraadt 475: {
1.15 millert 476: int i;
477: char *bp;
1.1 deraadt 478:
479: bp = buf;
480: if (bits8 == 0)
481: for (i = 0; i < n; i++) {
482: *bp = partab[(*bp) & 0177];
483: bp++;
484: }
485: if (write(fd, buf, n) < 0) {
486: if (errno == EIO)
487: tipabort("Lost carrier.");
488: /* this is questionable */
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.33 moritz 503: if (value(PARITY) == NULL)
1.1 deraadt 504: value(PARITY) = defparity;
505: parity = value(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: }