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