Annotation of src/usr.bin/tip/tip.c, Revision 1.40
1.40 ! nicm 1: /* $OpenBSD: tip.c,v 1.39 2010/06/29 05:55:37 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 */
60: setboolean(value(DC), TRUE);
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':
92: BR = atoi(&argv[1][1]);
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:
1.33 moritz 102: if (sys == NULL)
1.1 deraadt 103: goto notnumber;
1.27 deraadt 104: if (isalpha(*sys))
1.1 deraadt 105: goto notnumber;
106: /*
107: * System name is really a phone number...
108: * Copy the number then stomp on the original (in case the number
109: * is private, we don't want 'ps' or 'w' to find it).
110: */
1.27 deraadt 111: if (strlen(sys) > sizeof PNbuf - 1) {
1.13 millert 112: fprintf(stderr, "%s: phone number too long (max = %d bytes)\n",
1.14 pvalchev 113: __progname, (int)sizeof(PNbuf) - 1);
1.1 deraadt 114: exit(1);
115: }
1.27 deraadt 116: strlcpy(PNbuf, sys, sizeof PNbuf - 1);
117: for (p = sys; *p; p++)
1.1 deraadt 118: *p = '\0';
119: PN = PNbuf;
1.8 deraadt 120: (void)snprintf(sbuf, sizeof(sbuf), "tip%ld", BR);
1.27 deraadt 121: sys = sbuf;
1.1 deraadt 122:
123: notnumber:
124: (void)signal(SIGINT, cleanup);
125: (void)signal(SIGQUIT, cleanup);
126: (void)signal(SIGHUP, cleanup);
127: (void)signal(SIGTERM, cleanup);
1.24 otto 128: (void)signal(SIGCHLD, SIG_DFL);
1.1 deraadt 129:
1.27 deraadt 130: if ((i = hunt(sys)) == 0) {
1.1 deraadt 131: printf("all ports busy\n");
132: exit(3);
133: }
134: if (i == -1) {
135: printf("link down\n");
136: (void)uu_unlock(uucplock);
137: exit(3);
138: }
139: setbuf(stdout, NULL);
140: loginit();
141: vinit(); /* init variables */
1.12 millert 142: setparity("none"); /* set the parity table */
1.1 deraadt 143:
144: /*
145: * Hardwired connections require the
146: * line speed set before they make any transmissions
147: * (this is particularly true of things like a DF03-AC)
148: */
1.19 millert 149: if (HW && ttysetup(number(value(BAUDRATE)))) {
150: fprintf(stderr, "%s: bad baud rate %ld\n", __progname,
151: number(value(BAUDRATE)));
152: (void)uu_unlock(uucplock);
153: exit(3);
154: }
1.40 ! nicm 155: con();
1.19 millert 156: if (!HW && ttysetup(number(value(BAUDRATE)))) {
157: fprintf(stderr, "%s: bad baud rate %ld\n", __progname,
158: number(value(BAUDRATE)));
159: (void)uu_unlock(uucplock);
160: exit(3);
161: }
1.1 deraadt 162: cucommon:
163: /*
164: * From here down the code is shared with
165: * the "cu" version of tip.
166: */
1.10 jason 167:
168: i = fcntl(FD, F_GETFL);
169: if (i == -1) {
170: perror("fcntl");
1.23 deraadt 171: cleanup(0);
1.10 jason 172: }
173: i = fcntl(FD, F_SETFL, i & ~O_NONBLOCK);
174: if (i == -1) {
175: perror("fcntl");
1.23 deraadt 176: cleanup(0);
1.10 jason 177: }
1.1 deraadt 178:
1.2 deraadt 179: tcgetattr(0, &defterm);
1.22 deraadt 180: gotdefterm = 1;
1.2 deraadt 181: term = defterm;
182: term.c_lflag &= ~(ICANON|IEXTEN|ECHO);
183: term.c_iflag &= ~(INPCK|ICRNL);
184: term.c_oflag &= ~OPOST;
185: term.c_cc[VMIN] = 1;
186: term.c_cc[VTIME] = 0;
187: defchars = term;
188: term.c_cc[VINTR] = term.c_cc[VQUIT] = term.c_cc[VSUSP] =
1.25 deraadt 189: term.c_cc[VDSUSP] = term.c_cc[VDISCARD] =
190: term.c_cc[VLNEXT] = _POSIX_VDISABLE;
1.1 deraadt 191: raw();
192:
193: (void)signal(SIGALRM, timeout);
1.29 deraadt 194:
195: if (value(LINEDISC) != TTYDISC) {
196: int ld = (int)value(LINEDISC);
197: ioctl(FD, TIOCSETD, &ld);
198: }
1.1 deraadt 199:
1.36 nicm 200: if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0) {
201: (void)uu_unlock(uucplock);
202: err(3, "socketpair");
203: }
204:
1.1 deraadt 205: /*
206: * Everything's set up now:
207: * connection established (hardwired or dialup)
208: * line conditioned (baud rate, mode, etc.)
209: * internal data structures (variables)
210: * so, fork one process for local side and one for remote.
211: */
212: printf(cumode ? "Connected\r\n" : "\07connected\r\n");
1.23 deraadt 213: tipin_pid = getpid();
1.36 nicm 214: switch (tipout_pid = fork()) {
215: case -1:
216: (void)uu_unlock(uucplock);
217: err(3, "fork");
218: case 0:
219: close(pair[1]);
220: tipin_fd = pair[0];
221: tipout();
222: default:
223: close(pair[0]);
224: tipout_fd = pair[1];
1.1 deraadt 225: tipin();
1.36 nicm 226: }
1.1 deraadt 227: /*NOTREACHED*/
1.8 deraadt 228: exit(0);
1.40 ! nicm 229: }
! 230:
! 231: void
! 232: con(void)
! 233: {
! 234: if (CM != NULL)
! 235: parwrite(FD, CM, size(CM));
! 236: logent(value(HOST), DV, "call completed");
1.1 deraadt 237: }
238:
239: void
1.23 deraadt 240: cleanup(int signo)
1.1 deraadt 241: {
242: (void)uu_unlock(uucplock);
243: if (odisc)
1.27 deraadt 244: ioctl(0, TIOCSETD, &odisc);
1.22 deraadt 245: unraw();
1.23 deraadt 246: if (signo && tipout_pid) {
247: kill(tipout_pid, signo);
248: wait(NULL);
249: }
1.1 deraadt 250: exit(0);
251: }
252:
253: /*
254: * put the controlling keyboard into raw mode
255: */
1.8 deraadt 256: void
1.25 deraadt 257: raw(void)
1.1 deraadt 258: {
1.2 deraadt 259: tcsetattr(0, TCSADRAIN, &term);
1.1 deraadt 260: }
261:
262:
263: /*
264: * return keyboard to normal mode
265: */
1.8 deraadt 266: void
1.25 deraadt 267: unraw(void)
1.1 deraadt 268: {
1.22 deraadt 269: if (gotdefterm)
270: tcsetattr(0, TCSADRAIN, &defterm);
1.1 deraadt 271: }
272:
273: static jmp_buf promptbuf;
274:
275: /*
276: * Print string ``s'', then read a string
277: * in from the terminal. Handles signals & allows use of
278: * normal erase and kill characters.
279: */
1.8 deraadt 280: int
1.25 deraadt 281: prompt(char *s, char *p, size_t sz)
1.1 deraadt 282: {
1.15 millert 283: int c;
284: char *b = p;
1.1 deraadt 285: sig_t oint, oquit;
286:
287: stoprompt = 0;
288: oint = signal(SIGINT, intprompt);
289: oquit = signal(SIGQUIT, SIG_IGN);
290: unraw();
291: printf("%s", s);
292: if (setjmp(promptbuf) == 0)
1.6 millert 293: while ((c = getchar()) != EOF && (*p = c) != '\n' && --sz > 0)
1.1 deraadt 294: p++;
295: *p = '\0';
296:
297: raw();
298: (void)signal(SIGINT, oint);
299: (void)signal(SIGQUIT, oquit);
300: return (stoprompt || p == b);
301: }
302:
303: /*
304: * Interrupt service routine during prompting
305: */
1.27 deraadt 306: /*ARGSUSED*/
1.26 moritz 307: static void
308: intprompt(int signo)
1.1 deraadt 309: {
310: (void)signal(SIGINT, SIG_IGN);
311: stoprompt = 1;
312: printf("\r\n");
313: longjmp(promptbuf, 1);
314: }
315:
316: /*
317: * ****TIPIN TIPIN****
318: */
1.26 moritz 319: static void
1.25 deraadt 320: tipin(void)
1.1 deraadt 321: {
1.27 deraadt 322: int bol = 1;
1.16 deraadt 323: int gch;
1.17 deraadt 324: char ch;
1.1 deraadt 325:
326: /*
327: * Kinda klugey here...
328: * check for scripting being turned on from the .tiprc file,
329: * but be careful about just using setscript(), as we may
330: * send a SIGEMT before tipout has a chance to set up catching
331: * it; so wait a second, then setscript()
332: */
333: if (boolean(value(SCRIPT))) {
334: sleep(1);
335: setscript();
336: }
337:
338: while (1) {
1.2 deraadt 339: gch = getchar()&STRIP_PAR;
1.16 deraadt 340: /* XXX does not check for EOF */
1.1 deraadt 341: if ((gch == character(value(ESCAPE))) && bol) {
1.9 todd 342: if (!noesc) {
343: if (!(gch = escape()))
344: continue;
345: }
1.1 deraadt 346: } else if (!cumode && gch == character(value(RAISECHAR))) {
1.4 millert 347: setboolean(value(RAISE), !boolean(value(RAISE)));
1.1 deraadt 348: continue;
349: } else if (gch == '\r') {
350: bol = 1;
1.17 deraadt 351: ch = gch;
352: parwrite(FD, &ch, 1);
1.1 deraadt 353: if (boolean(value(HALFDUPLEX)))
354: printf("\r\n");
355: continue;
356: } else if (!cumode && gch == character(value(FORCE)))
1.2 deraadt 357: gch = getchar()&STRIP_PAR;
1.1 deraadt 358: bol = any(gch, value(EOL));
359: if (boolean(value(RAISE)) && islower(gch))
360: gch = toupper(gch);
1.17 deraadt 361: ch = gch;
362: parwrite(FD, &ch, 1);
1.1 deraadt 363: if (boolean(value(HALFDUPLEX)))
1.17 deraadt 364: printf("%c", ch);
1.1 deraadt 365: }
366: }
367:
368: extern esctable_t etable[];
369:
370: /*
371: * Escape handler --
372: * called on recognition of ``escapec'' at the beginning of a line
373: */
1.26 moritz 374: static int
1.25 deraadt 375: escape(void)
1.1 deraadt 376: {
1.16 deraadt 377: int gch;
1.15 millert 378: esctable_t *p;
1.1 deraadt 379: char c = character(value(ESCAPE));
380:
1.2 deraadt 381: gch = (getchar()&STRIP_PAR);
1.16 deraadt 382: /* XXX does not check for EOF */
1.1 deraadt 383: for (p = etable; p->e_char; p++)
384: if (p->e_char == gch) {
385: printf("%s", ctrl(c));
386: (*p->e_func)(gch);
387: return (0);
388: }
389: /* ESCAPE ESCAPE forces ESCAPE */
390: if (c != gch)
1.11 deraadt 391: parwrite(FD, &c, 1);
1.1 deraadt 392: return (gch);
393: }
394:
1.8 deraadt 395: int
1.25 deraadt 396: any(int cc, char *p)
1.1 deraadt 397: {
1.8 deraadt 398: char c = cc;
1.1 deraadt 399: while (p && *p)
400: if (*p++ == c)
401: return (1);
402: return (0);
403: }
404:
1.28 deraadt 405: size_t
1.25 deraadt 406: size(char *s)
1.1 deraadt 407: {
1.28 deraadt 408: size_t i = 0;
1.1 deraadt 409:
410: while (s && *s++)
411: i++;
412: return (i);
413: }
414:
415: char *
1.25 deraadt 416: interp(char *s)
1.1 deraadt 417: {
418: static char buf[256];
1.15 millert 419: char *p = buf, c, *q;
1.1 deraadt 420:
1.8 deraadt 421: while ((c = *s++)) {
1.1 deraadt 422: for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++)
423: if (*q++ == c) {
424: *p++ = '\\'; *p++ = *q;
425: goto next;
426: }
427: if (c < 040) {
428: *p++ = '^'; *p++ = c + 'A'-1;
429: } else if (c == 0177) {
430: *p++ = '^'; *p++ = '?';
431: } else
432: *p++ = c;
433: next:
434: ;
435: }
436: *p = '\0';
437: return (buf);
438: }
439:
440: char *
1.25 deraadt 441: ctrl(char c)
1.1 deraadt 442: {
443: static char s[3];
444:
445: if (c < 040 || c == 0177) {
446: s[0] = '^';
447: s[1] = c == 0177 ? '?' : c+'A'-1;
448: s[2] = '\0';
449: } else {
450: s[0] = c;
451: s[1] = '\0';
452: }
453: return (s);
454: }
455:
456: /*
457: * Help command
458: */
1.8 deraadt 459: void
1.26 moritz 460: help(int c)
1.1 deraadt 461: {
1.15 millert 462: esctable_t *p;
1.1 deraadt 463:
464: printf("%c\r\n", c);
465: for (p = etable; p->e_char; p++) {
466: printf("%2s", ctrl(character(value(ESCAPE))));
1.37 nicm 467: printf("%-2s %s\r\n", ctrl(p->e_char), p->e_help);
1.1 deraadt 468: }
469: }
470:
471: /*
472: * Set up the "remote" tty's state
473: */
1.19 millert 474: int
1.25 deraadt 475: ttysetup(int speed)
1.1 deraadt 476: {
1.2 deraadt 477: struct termios cntrl;
1.1 deraadt 478:
1.19 millert 479: if (tcgetattr(FD, &cntrl))
480: return (-1);
481: cfsetspeed(&cntrl, speed);
1.2 deraadt 482: cntrl.c_cflag &= ~(CSIZE|PARENB);
483: cntrl.c_cflag |= CS8;
1.5 millert 484: if (boolean(value(DC)))
485: cntrl.c_cflag |= CLOCAL;
1.21 millert 486: if (boolean(value(HARDWAREFLOW)))
1.25 deraadt 487: cntrl.c_cflag |= CRTSCTS;
1.2 deraadt 488: cntrl.c_iflag &= ~(ISTRIP|ICRNL);
489: cntrl.c_oflag &= ~OPOST;
490: cntrl.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO);
491: cntrl.c_cc[VMIN] = 1;
492: cntrl.c_cc[VTIME] = 0;
1.1 deraadt 493: if (boolean(value(TAND)))
1.2 deraadt 494: cntrl.c_iflag |= IXOFF;
1.19 millert 495: return (tcsetattr(FD, TCSAFLUSH, &cntrl));
1.1 deraadt 496: }
497:
498: static char partab[0200];
499:
500: /*
501: * Do a write to the remote machine with the correct parity.
502: * We are doing 8 bit wide output, so we just generate a character
503: * with the right parity and output it.
504: */
1.8 deraadt 505: void
1.27 deraadt 506: parwrite(int fd, char *buf, size_t n)
1.1 deraadt 507: {
1.15 millert 508: int i;
509: char *bp;
1.1 deraadt 510:
511: bp = buf;
512: if (bits8 == 0)
513: for (i = 0; i < n; i++) {
514: *bp = partab[(*bp) & 0177];
515: bp++;
516: }
517: if (write(fd, buf, n) < 0) {
518: if (errno == EIO)
519: tipabort("Lost carrier.");
520: /* this is questionable */
521: perror("write");
522: }
523: }
524:
525: /*
526: * Build a parity table with appropriate high-order bit.
527: */
1.8 deraadt 528: void
1.25 deraadt 529: setparity(char *defparity)
1.1 deraadt 530: {
1.15 millert 531: int i, flip, clr, set;
1.1 deraadt 532: char *parity;
1.4 millert 533: extern const unsigned char evenpartab[];
1.1 deraadt 534:
1.33 moritz 535: if (value(PARITY) == NULL)
1.1 deraadt 536: value(PARITY) = defparity;
537: parity = value(PARITY);
1.39 nicm 538: if (strcmp(parity, "none") == 0) {
1.1 deraadt 539: bits8 = 1;
540: return;
541: }
542: bits8 = 0;
543: flip = 0;
544: clr = 0377;
545: set = 0;
1.39 nicm 546: if (strcmp(parity, "odd") == 0)
1.1 deraadt 547: flip = 0200; /* reverse bit 7 */
1.39 nicm 548: else if (strcmp(parity, "zero") == 0)
1.1 deraadt 549: clr = 0177; /* turn off bit 7 */
1.39 nicm 550: else if (strcmp(parity, "one") == 0)
1.1 deraadt 551: set = 0200; /* turn on bit 7 */
1.39 nicm 552: else if (strcmp(parity, "even") != 0) {
1.1 deraadt 553: (void) fprintf(stderr, "%s: unknown parity value\r\n", parity);
554: (void) fflush(stderr);
555: }
556: for (i = 0; i < 0200; i++)
1.18 hugh 557: partab[i] = ((evenpartab[i] ^ flip) | set) & clr;
1.1 deraadt 558: }