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