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