1161754Sru/* $OpenBSD: tip.c,v 1.30 2006/08/18 03:06:18 jason Exp $ */ 288276Smarkm/* $NetBSD: tip.c,v 1.13 1997/04/20 00:03:05 mellon Exp $ */ 388276Smarkm 47527Sjkh/* 57527Sjkh * Copyright (c) 1983, 1993 67527Sjkh * The Regents of the University of California. All rights reserved. 77527Sjkh * 87527Sjkh * Redistribution and use in source and binary forms, with or without 97527Sjkh * modification, are permitted provided that the following conditions 107527Sjkh * are met: 117527Sjkh * 1. Redistributions of source code must retain the above copyright 127527Sjkh * notice, this list of conditions and the following disclaimer. 137527Sjkh * 2. Redistributions in binary form must reproduce the above copyright 147527Sjkh * notice, this list of conditions and the following disclaimer in the 157527Sjkh * documentation and/or other materials provided with the distribution. 16161754Sru * 3. Neither the name of the University nor the names of its contributors 177527Sjkh * may be used to endorse or promote products derived from this software 187527Sjkh * without specific prior written permission. 197527Sjkh * 207527Sjkh * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 217527Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 227527Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 237527Sjkh * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 247527Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 257527Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 267527Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 277527Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 287527Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 297527Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 307527Sjkh * SUCH DAMAGE. 317527Sjkh */ 327527Sjkh 3388276Smarkm#include <sys/cdefs.h> 3488276Smarkm__FBSDID("$FreeBSD: stable/10/usr.bin/tip/tip/tip.c 357518 2020-02-04 19:24:10Z dim $"); 3588276Smarkm 367527Sjkh#ifndef lint 37161754Srustatic const char copyright[] = 387527Sjkh"@(#) Copyright (c) 1983, 1993\n\ 397527Sjkh The Regents of the University of California. All rights reserved.\n"; 407527Sjkh#endif /* not lint */ 417527Sjkh 427527Sjkh#ifndef lint 4328365Scharnier#if 0 447527Sjkhstatic char sccsid[] = "@(#)tip.c 8.1 (Berkeley) 6/6/93"; 45161754Srustatic const char rcsid[] = "$OpenBSD: tip.c,v 1.30 2006/08/18 03:06:18 jason Exp $"; 4628365Scharnier#endif 477527Sjkh#endif /* not lint */ 487527Sjkh 497527Sjkh/* 507527Sjkh * tip - UNIX link to other systems 517527Sjkh * tip [-v] [-speed] system-name 527527Sjkh * or 537527Sjkh * cu phone-number [-s speed] [-l line] [-a acu] 547527Sjkh */ 557527Sjkh#include "tip.h" 567527Sjkh#include "pathnames.h" 577527Sjkh 5888276Smarkmint disc = TTYDISC; /* tip normally runs this way */ 597527Sjkhchar PNbuf[256]; /* This limits the size of a number */ 607527Sjkh 61161754Srustatic void intprompt(int); 62161754Srustatic void tipin(void); 63161754Srustatic int escape(void); 64161754Sru 6551287Speterint 66161754Srumain(int argc, char *argv[]) 677527Sjkh{ 68161754Sru char *sys = NOSTR, sbuf[12], *p; 6988276Smarkm int i; 707527Sjkh 71161754Sru /* XXX preserve previous braindamaged behavior */ 72161754Sru setboolean(value(DC), TRUE); 73161754Sru 747527Sjkh gid = getgid(); 757527Sjkh egid = getegid(); 767527Sjkh uid = getuid(); 777527Sjkh euid = geteuid(); 7888276Smarkm if (equal(__progname, "cu")) { 797527Sjkh cumode = 1; 807527Sjkh cumain(argc, argv); 817527Sjkh goto cucommon; 827527Sjkh } 837527Sjkh 8488276Smarkm if (argc > 4) { 8588276Smarkm fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n"); 8688276Smarkm exit(1); 8788276Smarkm } 8888276Smarkm if (!isatty(0)) { 8988276Smarkm fprintf(stderr, "%s: must be interactive\n", __progname); 9088276Smarkm exit(1); 9188276Smarkm } 927527Sjkh 937527Sjkh for (; argc > 1; argv++, argc--) { 947527Sjkh if (argv[1][0] != '-') 95161754Sru sys = argv[1]; 967527Sjkh else switch (argv[1][1]) { 977527Sjkh 987527Sjkh case 'v': 997527Sjkh vflag++; 1007527Sjkh break; 1017527Sjkh 10288276Smarkm case 'n': 10388276Smarkm noesc++; 10488276Smarkm break; 10588276Smarkm 1067527Sjkh case '0': case '1': case '2': case '3': case '4': 1077527Sjkh case '5': case '6': case '7': case '8': case '9': 1087527Sjkh BR = atoi(&argv[1][1]); 1097527Sjkh break; 1107527Sjkh 1117527Sjkh default: 11288276Smarkm fprintf(stderr, "%s: %s, unknown option\n", __progname, 11388276Smarkm argv[1]); 1147527Sjkh break; 1157527Sjkh } 1167527Sjkh } 1177527Sjkh 118161754Sru if (sys == NOSTR) 1197527Sjkh goto notnumber; 120161754Sru if (isalpha(*sys)) 1217527Sjkh goto notnumber; 1227527Sjkh /* 1237527Sjkh * System name is really a phone number... 1247527Sjkh * Copy the number then stomp on the original (in case the number 1257527Sjkh * is private, we don't want 'ps' or 'w' to find it). 1267527Sjkh */ 127161754Sru if (strlen(sys) > sizeof PNbuf - 1) { 12888276Smarkm fprintf(stderr, "%s: phone number too long (max = %d bytes)\n", 12988276Smarkm __progname, (int)sizeof(PNbuf) - 1); 13088276Smarkm exit(1); 13188276Smarkm } 132161754Sru strlcpy(PNbuf, sys, sizeof PNbuf - 1); 133161754Sru for (p = sys; *p; p++) 1347527Sjkh *p = '\0'; 1357527Sjkh PN = PNbuf; 13636791Simp (void)snprintf(sbuf, sizeof(sbuf), "tip%ld", BR); 137161754Sru sys = sbuf; 1387527Sjkh 1397527Sjkhnotnumber: 1407527Sjkh (void)signal(SIGINT, cleanup); 1417527Sjkh (void)signal(SIGQUIT, cleanup); 1427527Sjkh (void)signal(SIGHUP, cleanup); 1437527Sjkh (void)signal(SIGTERM, cleanup); 144161754Sru (void)signal(SIGCHLD, SIG_DFL); 1457527Sjkh 146161754Sru if ((i = hunt(sys)) == 0) { 1477527Sjkh printf("all ports busy\n"); 1487527Sjkh exit(3); 1497527Sjkh } 1507527Sjkh if (i == -1) { 1517527Sjkh printf("link down\n"); 1527527Sjkh (void)uu_unlock(uucplock); 1537527Sjkh exit(3); 1547527Sjkh } 1557527Sjkh setbuf(stdout, NULL); 1567527Sjkh loginit(); 1577527Sjkh 1587527Sjkh /* 15988276Smarkm * Now that we have the logfile and the ACU open 16088276Smarkm * return to the real uid and gid. These things will 16188276Smarkm * be closed on exit. Swap real and effective uid's 16288276Smarkm * so we can get the original permissions back 16388276Smarkm * for removing the uucp lock. 16488276Smarkm */ 16588276Smarkm user_uid(); 16688276Smarkm 16788276Smarkm /* 1687527Sjkh * Kludge, their's no easy way to get the initialization 1697527Sjkh * in the right order, so force it here 1707527Sjkh */ 1717527Sjkh if ((PH = getenv("PHONES")) == NOSTR) 1727527Sjkh PH = _PATH_PHONES; 1737527Sjkh vinit(); /* init variables */ 17488276Smarkm setparity("none"); /* set the parity table */ 1757527Sjkh 1767527Sjkh /* 1777527Sjkh * Hardwired connections require the 1787527Sjkh * line speed set before they make any transmissions 1797527Sjkh * (this is particularly true of things like a DF03-AC) 1807527Sjkh */ 181161754Sru if (HW && ttysetup(number(value(BAUDRATE)))) { 182161754Sru fprintf(stderr, "%s: bad baud rate %ld\n", __progname, 183161754Sru number(value(BAUDRATE))); 1847527Sjkh daemon_uid(); 1857527Sjkh (void)uu_unlock(uucplock); 186161754Sru exit(3); 187161754Sru } 188161754Sru if ((p = con())) { 189161754Sru printf("\07%s\n[EOT]\n", p); 190161754Sru daemon_uid(); 191161754Sru (void)uu_unlock(uucplock); 1927527Sjkh exit(1); 1937527Sjkh } 194161754Sru if (!HW && ttysetup(number(value(BAUDRATE)))) { 195161754Sru fprintf(stderr, "%s: bad baud rate %ld\n", __progname, 196161754Sru number(value(BAUDRATE))); 197161754Sru daemon_uid(); 198161754Sru (void)uu_unlock(uucplock); 199161754Sru exit(3); 200161754Sru } 20188276Smarkmcucommon: 2027527Sjkh /* 2037527Sjkh * From here down the code is shared with 2047527Sjkh * the "cu" version of tip. 2057527Sjkh */ 2067527Sjkh 20788276Smarkm i = fcntl(FD, F_GETFL); 20888276Smarkm if (i == -1) { 20988276Smarkm perror("fcntl"); 210161754Sru cleanup(0); 21188276Smarkm } 21288276Smarkm i = fcntl(FD, F_SETFL, i & ~O_NONBLOCK); 21388276Smarkm if (i == -1) { 21488276Smarkm perror("fcntl"); 215161754Sru cleanup(0); 21688276Smarkm } 21788276Smarkm 21888276Smarkm tcgetattr(0, &defterm); 219161754Sru gotdefterm = 1; 22088276Smarkm term = defterm; 22188276Smarkm term.c_lflag &= ~(ICANON|IEXTEN|ECHO); 22288276Smarkm term.c_iflag &= ~(INPCK|ICRNL); 22388276Smarkm term.c_oflag &= ~OPOST; 22488276Smarkm term.c_cc[VMIN] = 1; 22588276Smarkm term.c_cc[VTIME] = 0; 22688276Smarkm defchars = term; 22788276Smarkm term.c_cc[VINTR] = term.c_cc[VQUIT] = term.c_cc[VSUSP] = 228161754Sru term.c_cc[VDSUSP] = term.c_cc[VDISCARD] = 229161754Sru term.c_cc[VLNEXT] = _POSIX_VDISABLE; 2307527Sjkh raw(); 2317527Sjkh 2327527Sjkh pipe(fildes); pipe(repdes); 2337527Sjkh (void)signal(SIGALRM, timeout); 2347527Sjkh 235161754Sru if (value(LINEDISC) != TTYDISC) { 236161781Sru int ld = (int)(intptr_t)value(LINEDISC); 237161754Sru ioctl(FD, TIOCSETD, &ld); 238161754Sru } 239161754Sru 2407527Sjkh /* 2417527Sjkh * Everything's set up now: 2427527Sjkh * connection established (hardwired or dialup) 2437527Sjkh * line conditioned (baud rate, mode, etc.) 2447527Sjkh * internal data structures (variables) 2457527Sjkh * so, fork one process for local side and one for remote. 2467527Sjkh */ 2477527Sjkh printf(cumode ? "Connected\r\n" : "\07connected\r\n"); 248161754Sru tipin_pid = getpid(); 249161754Sru if ((tipout_pid = fork())) 2507527Sjkh tipin(); 2517527Sjkh else 2527527Sjkh tipout(); 2537527Sjkh /*NOTREACHED*/ 25488276Smarkm exit(0); 2557527Sjkh} 2567527Sjkh 2577527Sjkhvoid 258161754Srucleanup(int signo) 2597527Sjkh{ 2607527Sjkh daemon_uid(); 2617527Sjkh (void)uu_unlock(uucplock); 2627527Sjkh if (odisc) 263161754Sru ioctl(0, TIOCSETD, &odisc); 264161754Sru unraw(); 265161754Sru if (signo && tipout_pid) { 266161754Sru kill(tipout_pid, signo); 267161754Sru wait(NULL); 268161754Sru } 2697527Sjkh exit(0); 2707527Sjkh} 2717527Sjkh 2727527Sjkh/* 2737527Sjkh * Muck with user ID's. We are setuid to the owner of the lock 2747527Sjkh * directory when we start. user_uid() reverses real and effective 2757527Sjkh * ID's after startup, to run with the user's permissions. 2767527Sjkh * daemon_uid() switches back to the privileged uid for unlocking. 2777527Sjkh * Finally, to avoid running a shell with the wrong real uid, 2787527Sjkh * shell_uid() sets real and effective uid's to the user's real ID. 2797527Sjkh */ 2807527Sjkhstatic int uidswapped; 2817527Sjkh 28228365Scharniervoid 283161754Sruuser_uid(void) 2847527Sjkh{ 2857527Sjkh if (uidswapped == 0) { 2867527Sjkh seteuid(uid); 2877527Sjkh uidswapped = 1; 2887527Sjkh } 2897527Sjkh} 2907527Sjkh 29128365Scharniervoid 292161754Srudaemon_uid(void) 2937527Sjkh{ 29488276Smarkm 2957527Sjkh if (uidswapped) { 2967527Sjkh seteuid(euid); 2977527Sjkh uidswapped = 0; 2987527Sjkh } 2997527Sjkh} 3007527Sjkh 30128365Scharniervoid 302161754Srushell_uid(void) 3037527Sjkh{ 30436791Simp setegid(gid); 3057527Sjkh seteuid(uid); 3067527Sjkh} 3077527Sjkh 3087527Sjkh/* 3097527Sjkh * put the controlling keyboard into raw mode 3107527Sjkh */ 3117527Sjkhvoid 312161754Sruraw(void) 3137527Sjkh{ 31488276Smarkm tcsetattr(0, TCSADRAIN, &term); 3157527Sjkh} 3167527Sjkh 3177527Sjkh 3187527Sjkh/* 3197527Sjkh * return keyboard to normal mode 3207527Sjkh */ 32128365Scharniervoid 322161754Sruunraw(void) 3237527Sjkh{ 324161754Sru if (gotdefterm) 325161754Sru tcsetattr(0, TCSADRAIN, &defterm); 3267527Sjkh} 3277527Sjkh 328178736Sbms/* 329178736Sbms * give up exclusive tty access 330178736Sbms */ 331178736Sbmsvoid 332178736Sbmsunexcl() 333178736Sbms{ 334178736Sbms ioctl(FD, TIOCNXCL, 0); 335178736Sbms} 336178736Sbms 3377527Sjkhstatic jmp_buf promptbuf; 3387527Sjkh 3397527Sjkh/* 3407527Sjkh * Print string ``s'', then read a string 3417527Sjkh * in from the terminal. Handles signals & allows use of 3427527Sjkh * normal erase and kill characters. 3437527Sjkh */ 34428365Scharnierint 345161754Sruprompt(char *s, char *p, size_t sz) 3467527Sjkh{ 34788276Smarkm int c; 34888276Smarkm char *b = p; 3497527Sjkh sig_t oint, oquit; 3507527Sjkh 3517527Sjkh stoprompt = 0; 3527527Sjkh oint = signal(SIGINT, intprompt); 3537527Sjkh oquit = signal(SIGQUIT, SIG_IGN); 3547527Sjkh unraw(); 3557527Sjkh printf("%s", s); 3567527Sjkh if (setjmp(promptbuf) == 0) 35788276Smarkm while ((c = getchar()) != EOF && (*p = c) != '\n' && --sz > 0) 3587527Sjkh p++; 3597527Sjkh *p = '\0'; 3607527Sjkh 3617527Sjkh raw(); 3627527Sjkh (void)signal(SIGINT, oint); 3637527Sjkh (void)signal(SIGQUIT, oquit); 3647527Sjkh return (stoprompt || p == b); 3657527Sjkh} 3667527Sjkh 3677527Sjkh/* 3687527Sjkh * Interrupt service routine during prompting 3697527Sjkh */ 370161754Sru/*ARGSUSED*/ 371161754Srustatic void 372161754Sruintprompt(int signo) 3737527Sjkh{ 3747527Sjkh (void)signal(SIGINT, SIG_IGN); 3757527Sjkh stoprompt = 1; 3767527Sjkh printf("\r\n"); 3777527Sjkh longjmp(promptbuf, 1); 3787527Sjkh} 3797527Sjkh 3807527Sjkh/* 3817527Sjkh * ****TIPIN TIPIN**** 3827527Sjkh */ 383161754Srustatic void 384161754Srutipin(void) 3857527Sjkh{ 386161754Sru int bol = 1; 387161754Sru int gch; 388161754Sru char ch; 3897527Sjkh 3907527Sjkh /* 3917527Sjkh * Kinda klugey here... 3927527Sjkh * check for scripting being turned on from the .tiprc file, 3937527Sjkh * but be careful about just using setscript(), as we may 3947527Sjkh * send a SIGEMT before tipout has a chance to set up catching 3957527Sjkh * it; so wait a second, then setscript() 3967527Sjkh */ 3977527Sjkh if (boolean(value(SCRIPT))) { 3987527Sjkh sleep(1); 3997527Sjkh setscript(); 4007527Sjkh } 4017527Sjkh 4027527Sjkh while (1) { 40388276Smarkm gch = getchar()&STRIP_PAR; 404161754Sru /* XXX does not check for EOF */ 4057527Sjkh if ((gch == character(value(ESCAPE))) && bol) { 40688276Smarkm if (!noesc) { 40788276Smarkm if (!(gch = escape())) 40888276Smarkm continue; 40988276Smarkm } 4107527Sjkh } else if (!cumode && gch == character(value(RAISECHAR))) { 41188276Smarkm setboolean(value(RAISE), !boolean(value(RAISE))); 4127527Sjkh continue; 4137527Sjkh } else if (gch == '\r') { 4147527Sjkh bol = 1; 415161754Sru ch = gch; 416161754Sru parwrite(FD, &ch, 1); 4177527Sjkh if (boolean(value(HALFDUPLEX))) 4187527Sjkh printf("\r\n"); 4197527Sjkh continue; 420357518Sdim } else if (!cumode && gch == character(value(FORCE))) { 42188276Smarkm gch = getchar()&STRIP_PAR; 422357518Sdim } 4237527Sjkh bol = any(gch, value(EOL)); 4247527Sjkh if (boolean(value(RAISE)) && islower(gch)) 4257527Sjkh gch = toupper(gch); 426161754Sru ch = gch; 427161754Sru parwrite(FD, &ch, 1); 4287527Sjkh if (boolean(value(HALFDUPLEX))) 429161754Sru printf("%c", ch); 4307527Sjkh } 4317527Sjkh} 4327527Sjkh 4337527Sjkhextern esctable_t etable[]; 4347527Sjkh 4357527Sjkh/* 4367527Sjkh * Escape handler -- 4377527Sjkh * called on recognition of ``escapec'' at the beginning of a line 4387527Sjkh */ 439161754Srustatic int 440161754Sruescape(void) 4417527Sjkh{ 442161754Sru int gch; 44388276Smarkm esctable_t *p; 4447527Sjkh char c = character(value(ESCAPE)); 4457527Sjkh 44688276Smarkm gch = (getchar()&STRIP_PAR); 447161754Sru /* XXX does not check for EOF */ 4487527Sjkh for (p = etable; p->e_char; p++) 4497527Sjkh if (p->e_char == gch) { 4507527Sjkh if ((p->e_flags&PRIV) && uid) 4517527Sjkh continue; 4527527Sjkh printf("%s", ctrl(c)); 4537527Sjkh (*p->e_func)(gch); 4547527Sjkh return (0); 4557527Sjkh } 4567527Sjkh /* ESCAPE ESCAPE forces ESCAPE */ 4577527Sjkh if (c != gch) 45888276Smarkm parwrite(FD, &c, 1); 4597527Sjkh return (gch); 4607527Sjkh} 4617527Sjkh 46228365Scharnierint 463161754Sruany(int cc, char *p) 4647527Sjkh{ 46588276Smarkm char c = cc; 4667527Sjkh while (p && *p) 4677527Sjkh if (*p++ == c) 4687527Sjkh return (1); 4697527Sjkh return (0); 4707527Sjkh} 4717527Sjkh 472161754Srusize_t 473161754Srusize(char *s) 4747527Sjkh{ 475161754Sru size_t i = 0; 4767527Sjkh 4777527Sjkh while (s && *s++) 4787527Sjkh i++; 4797527Sjkh return (i); 4807527Sjkh} 4817527Sjkh 4827527Sjkhchar * 483161754Sruinterp(char *s) 4847527Sjkh{ 4857527Sjkh static char buf[256]; 48688276Smarkm char *p = buf, c, *q; 4877527Sjkh 48828365Scharnier while ((c = *s++)) { 4897527Sjkh for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++) 4907527Sjkh if (*q++ == c) { 4917527Sjkh *p++ = '\\'; *p++ = *q; 4927527Sjkh goto next; 4937527Sjkh } 4947527Sjkh if (c < 040) { 4957527Sjkh *p++ = '^'; *p++ = c + 'A'-1; 4967527Sjkh } else if (c == 0177) { 4977527Sjkh *p++ = '^'; *p++ = '?'; 4987527Sjkh } else 4997527Sjkh *p++ = c; 5007527Sjkh next: 5017527Sjkh ; 5027527Sjkh } 5037527Sjkh *p = '\0'; 5047527Sjkh return (buf); 5057527Sjkh} 5067527Sjkh 5077527Sjkhchar * 508161754Sructrl(char c) 5097527Sjkh{ 5107527Sjkh static char s[3]; 5117527Sjkh 5127527Sjkh if (c < 040 || c == 0177) { 5137527Sjkh s[0] = '^'; 5147527Sjkh s[1] = c == 0177 ? '?' : c+'A'-1; 5157527Sjkh s[2] = '\0'; 5167527Sjkh } else { 5177527Sjkh s[0] = c; 5187527Sjkh s[1] = '\0'; 5197527Sjkh } 5207527Sjkh return (s); 5217527Sjkh} 5227527Sjkh 5237527Sjkh/* 5247527Sjkh * Help command 5257527Sjkh */ 52628365Scharniervoid 527161754Sruhelp(int c) 5287527Sjkh{ 52988276Smarkm esctable_t *p; 5307527Sjkh 5317527Sjkh printf("%c\r\n", c); 5327527Sjkh for (p = etable; p->e_char; p++) { 5337527Sjkh if ((p->e_flags&PRIV) && uid) 5347527Sjkh continue; 5357527Sjkh printf("%2s", ctrl(character(value(ESCAPE)))); 5367527Sjkh printf("%-2s %c %s\r\n", ctrl(p->e_char), 5377527Sjkh p->e_flags&EXP ? '*': ' ', p->e_help); 5387527Sjkh } 5397527Sjkh} 5407527Sjkh 5417527Sjkh/* 5427527Sjkh * Set up the "remote" tty's state 5437527Sjkh */ 544161754Sruint 545161754Sruttysetup(int speed) 5467527Sjkh{ 54788276Smarkm struct termios cntrl; 5487527Sjkh 549161754Sru if (tcgetattr(FD, &cntrl)) 550161754Sru return (-1); 551161754Sru cfsetspeed(&cntrl, speed); 55288276Smarkm cntrl.c_cflag &= ~(CSIZE|PARENB); 55388276Smarkm cntrl.c_cflag |= CS8; 55488276Smarkm if (boolean(value(DC))) 55588276Smarkm cntrl.c_cflag |= CLOCAL; 556161754Sru if (boolean(value(HARDWAREFLOW))) 557161754Sru cntrl.c_cflag |= CRTSCTS; 55888276Smarkm cntrl.c_iflag &= ~(ISTRIP|ICRNL); 55988276Smarkm cntrl.c_oflag &= ~OPOST; 56088276Smarkm cntrl.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO); 56188276Smarkm cntrl.c_cc[VMIN] = 1; 56288276Smarkm cntrl.c_cc[VTIME] = 0; 5637527Sjkh if (boolean(value(TAND))) 56488276Smarkm cntrl.c_iflag |= IXOFF; 565161754Sru return (tcsetattr(FD, TCSAFLUSH, &cntrl)); 5667527Sjkh} 5677527Sjkh 5687527Sjkhstatic char partab[0200]; 5697527Sjkh 5707527Sjkh/* 5717527Sjkh * Do a write to the remote machine with the correct parity. 5727527Sjkh * We are doing 8 bit wide output, so we just generate a character 5737527Sjkh * with the right parity and output it. 5747527Sjkh */ 57528365Scharniervoid 576161754Sruparwrite(int fd, char *buf, size_t n) 5777527Sjkh{ 578161781Sru size_t i; 57988276Smarkm char *bp; 5807527Sjkh 5817527Sjkh bp = buf; 5827527Sjkh if (bits8 == 0) 5837527Sjkh for (i = 0; i < n; i++) { 5847527Sjkh *bp = partab[(*bp) & 0177]; 5857527Sjkh bp++; 5867527Sjkh } 5877527Sjkh if (write(fd, buf, n) < 0) { 588230654Sphk if (errno == EIO || errno == ENXIO) 5897527Sjkh tipabort("Lost carrier."); 59088276Smarkm /* this is questionable */ 59188276Smarkm perror("write"); 5927527Sjkh } 5937527Sjkh} 5947527Sjkh 5957527Sjkh/* 5967527Sjkh * Build a parity table with appropriate high-order bit. 5977527Sjkh */ 59828365Scharniervoid 599161754Srusetparity(char *defparity) 6007527Sjkh{ 60188276Smarkm int i, flip, clr, set; 6027527Sjkh char *parity; 60388276Smarkm extern const unsigned char evenpartab[]; 6047527Sjkh 6057527Sjkh if (value(PARITY) == NOSTR) 6067527Sjkh value(PARITY) = defparity; 6077527Sjkh parity = value(PARITY); 6087527Sjkh if (equal(parity, "none")) { 6097527Sjkh bits8 = 1; 6107527Sjkh return; 6117527Sjkh } 6127527Sjkh bits8 = 0; 6137527Sjkh flip = 0; 6147527Sjkh clr = 0377; 6157527Sjkh set = 0; 6167527Sjkh if (equal(parity, "odd")) 6177527Sjkh flip = 0200; /* reverse bit 7 */ 6187527Sjkh else if (equal(parity, "zero")) 6197527Sjkh clr = 0177; /* turn off bit 7 */ 6207527Sjkh else if (equal(parity, "one")) 6217527Sjkh set = 0200; /* turn on bit 7 */ 6227527Sjkh else if (!equal(parity, "even")) { 6237527Sjkh (void) fprintf(stderr, "%s: unknown parity value\r\n", parity); 6247527Sjkh (void) fflush(stderr); 6257527Sjkh } 6267527Sjkh for (i = 0; i < 0200; i++) 627161754Sru partab[i] = ((evenpartab[i] ^ flip) | set) & clr; 6287527Sjkh} 629