171333Sitojun/* $OpenBSD: tip.c,v 1.30 2006/08/18 03:06:18 jason Exp $ */ 2118968Sume/* $NetBSD: tip.c,v 1.13 1997/04/20 00:03:05 mellon Exp $ */ 362656Skris 455505Sshin/*- 555505Sshin * SPDX-License-Identifier: BSD-3-Clause 6224144Shrs * 755505Sshin * Copyright (c) 1983, 1993 8222732Shrs * The Regents of the University of California. All rights reserved. 955505Sshin * 1055505Sshin * Redistribution and use in source and binary forms, with or without 1155505Sshin * modification, are permitted provided that the following conditions 1255505Sshin * are met: 1355505Sshin * 1. Redistributions of source code must retain the above copyright 1455505Sshin * notice, this list of conditions and the following disclaimer. 1555505Sshin * 2. Redistributions in binary form must reproduce the above copyright 1655505Sshin * notice, this list of conditions and the following disclaimer in the 1755505Sshin * documentation and/or other materials provided with the distribution. 1855505Sshin * 3. Neither the name of the University nor the names of its contributors 1955505Sshin * may be used to endorse or promote products derived from this software 20222732Shrs * without specific prior written permission. 2155505Sshin * 2255505Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2355505Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2455505Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2555505Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2655505Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2755505Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2855505Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2955505Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3055505Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3155505Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3255505Sshin * SUCH DAMAGE. 3355505Sshin */ 3455505Sshin 3555505Sshin/* 3655505Sshin * tip - UNIX link to other systems 3755505Sshin * tip [-v] [-speed] system-name 3855505Sshin * or 3955505Sshin * cu phone-number [-s speed] [-l line] [-a acu] 4055505Sshin */ 4155505Sshin#define EXTERN 4255505Sshin#include "tip.h" 4355505Sshin#include "pathnames.h" 4455505Sshin 4557120Sshinint disc = TTYDISC; /* tip normally runs this way */ 4655505Sshinchar PNbuf[256]; /* This limits the size of a number */ 4757120Sshin 48151468Ssuzstatic void intprompt(int); 4955505Sshinstatic void tipin(void); 5055505Sshinstatic int escape(void); 5155505Sshin 5255505Sshinint 5355505Sshinmain(int argc, char *argv[]) 5455505Sshin{ 55224144Shrs char *sys = NOSTR, sbuf[12], *p; 56222732Shrs int i; 5755505Sshin 58136764Ssuz /* XXX preserve previous braindamaged behavior */ 5955505Sshin setboolean(value(DC), TRUE); 60253970Shrs 6155505Sshin gid = getgid(); 6278064Sume egid = getegid(); 6355505Sshin uid = getuid(); 6455505Sshin euid = geteuid(); 6555505Sshin if (equal(__progname, "cu")) { 6655505Sshin cumode = 1; 6755505Sshin cumain(argc, argv); 6855505Sshin goto cucommon; 6955505Sshin } 70222732Shrs 71222732Shrs if (argc > 4) { 72222732Shrs fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n"); 73222732Shrs exit(1); 74222732Shrs } 7598172Sume if (!isatty(0)) { 7698172Sume fprintf(stderr, "%s: must be interactive\n", __progname); 7798172Sume exit(1); 78173412Skevlo } 79222732Shrs 80222732Shrs for (; argc > 1; argv++, argc--) { 8155505Sshin if (argv[1][0] != '-') 82222732Shrs sys = argv[1]; 83222732Shrs else switch (argv[1][1]) { 84222732Shrs 8555505Sshin case 'v': 86222732Shrs vflag++; 87222732Shrs break; 88222732Shrs 8955505Sshin case 'n': 90222732Shrs noesc++; 91222732Shrs break; 92222732Shrs 93222732Shrs case '0': case '1': case '2': case '3': case '4': 94222732Shrs case '5': case '6': case '7': case '8': case '9': 95222732Shrs BR = atoi(&argv[1][1]); 96222732Shrs break; 97222732Shrs 98222732Shrs default: 99222732Shrs fprintf(stderr, "%s: %s, unknown option\n", __progname, 100222732Shrs argv[1]); 101222732Shrs break; 102222732Shrs } 103222732Shrs } 104222732Shrs 105222732Shrs if (sys == NOSTR) 106222732Shrs goto notnumber; 107222732Shrs if (isalpha(*sys)) 108222732Shrs goto notnumber; 109222732Shrs /* 110222732Shrs * System name is really a phone number... 111222732Shrs * Copy the number then stomp on the original (in case the number 112222732Shrs * is private, we don't want 'ps' or 'w' to find it). 113222732Shrs */ 114222743Shrs if (strlen(sys) > sizeof PNbuf - 1) { 115222732Shrs fprintf(stderr, "%s: phone number too long (max = %d bytes)\n", 116222732Shrs __progname, (int)sizeof(PNbuf) - 1); 117222732Shrs exit(1); 118222732Shrs } 11962656Skris strlcpy(PNbuf, sys, sizeof PNbuf - 1); 120118784Sume for (p = sys; *p; p++) 12155505Sshin *p = '\0'; 12255505Sshin PN = PNbuf; 12355505Sshin (void)snprintf(sbuf, sizeof(sbuf), "tip%ld", BR); 12455505Sshin sys = sbuf; 12555505Sshin 12655505Sshinnotnumber: 12762656Skris (void)signal(SIGINT, cleanup); 128222732Shrs (void)signal(SIGQUIT, cleanup); 129222732Shrs (void)signal(SIGHUP, cleanup); 13062656Skris (void)signal(SIGTERM, cleanup); 13155505Sshin (void)signal(SIGCHLD, SIG_DFL); 13255505Sshin 13362656Skris if ((i = hunt(sys)) == 0) { 13455505Sshin printf("all ports busy\n"); 135224144Shrs exit(3); 136224144Shrs } 137224144Shrs if (i == -1) { 138224144Shrs printf("link down\n"); 139222732Shrs (void)uu_unlock(uucplock); 140224144Shrs exit(3); 141224144Shrs } 142224144Shrs setbuf(stdout, NULL); 143224144Shrs loginit(); 144224144Shrs 145224144Shrs /* 146224144Shrs * Now that we have the logfile and the ACU open 147224144Shrs * return to the real uid and gid. These things will 148222732Shrs * be closed on exit. Swap real and effective uid's 149224144Shrs * so we can get the original permissions back 150222972Shrs * for removing the uucp lock. 151224144Shrs */ 152222972Shrs user_uid(); 153224144Shrs 154224144Shrs /* 155224144Shrs * Kludge, their's no easy way to get the initialization 156224144Shrs * in the right order, so force it here 157224144Shrs */ 158224144Shrs if ((PH = getenv("PHONES")) == NOSTR) 159224144Shrs PH = _PATH_PHONES; 160224144Shrs vinit(); /* init variables */ 161224144Shrs setparity("none"); /* set the parity table */ 162224144Shrs 163224144Shrs /* 164224144Shrs * Hardwired connections require the 165224144Shrs * line speed set before they make any transmissions 166224144Shrs * (this is particularly true of things like a DF03-AC) 167224144Shrs */ 168224144Shrs if (HW && ttysetup(number(value(BAUDRATE)))) { 169224144Shrs fprintf(stderr, "%s: bad baud rate %ld\n", __progname, 170224144Shrs number(value(BAUDRATE))); 171222972Shrs daemon_uid(); 172224144Shrs (void)uu_unlock(uucplock); 173224144Shrs exit(3); 174224144Shrs } 175222972Shrs if ((p = con())) { 176222972Shrs printf("\07%s\n[EOT]\n", p); 177224144Shrs daemon_uid(); 178222972Shrs (void)uu_unlock(uucplock); 179222972Shrs exit(1); 180224144Shrs } 181224144Shrs if (!HW && ttysetup(number(value(BAUDRATE)))) { 182224144Shrs fprintf(stderr, "%s: bad baud rate %ld\n", __progname, 183224144Shrs number(value(BAUDRATE))); 184222972Shrs daemon_uid(); 185224144Shrs (void)uu_unlock(uucplock); 186224144Shrs exit(3); 187222972Shrs } 188224144Shrscucommon: 189224144Shrs /* 190224144Shrs * From here down the code is shared with 191224144Shrs * the "cu" version of tip. 192224144Shrs */ 193224144Shrs 194224144Shrs i = fcntl(FD, F_GETFL); 195224144Shrs if (i == -1) { 196224144Shrs perror("fcntl"); 197224144Shrs cleanup(0); 198224144Shrs } 199224144Shrs i = fcntl(FD, F_SETFL, i & ~O_NONBLOCK); 200224144Shrs if (i == -1) { 201224144Shrs perror("fcntl"); 202224144Shrs cleanup(0); 203224144Shrs } 204224144Shrs 205224144Shrs tcgetattr(0, &defterm); 206224144Shrs gotdefterm = 1; 207224144Shrs term = defterm; 208224144Shrs term.c_lflag &= ~(ICANON|IEXTEN|ECHO); 209224144Shrs term.c_iflag &= ~(INPCK|ICRNL); 210224144Shrs term.c_oflag &= ~OPOST; 211224144Shrs term.c_cc[VMIN] = 1; 212224144Shrs term.c_cc[VTIME] = 0; 213224144Shrs defchars = term; 214224144Shrs term.c_cc[VINTR] = term.c_cc[VQUIT] = term.c_cc[VSUSP] = 215224144Shrs term.c_cc[VDSUSP] = term.c_cc[VDISCARD] = 216224144Shrs term.c_cc[VLNEXT] = _POSIX_VDISABLE; 217224144Shrs raw(); 218224144Shrs 219228990Suqs pipe(fildes); pipe(repdes); 220224144Shrs (void)signal(SIGALRM, timeout); 221224144Shrs 222224144Shrs if (value(LINEDISC) != TTYDISC) { 223224144Shrs int ld = (int)(intptr_t)value(LINEDISC); 224224144Shrs ioctl(FD, TIOCSETD, &ld); 225224144Shrs } 226224144Shrs 227224144Shrs /* 228224144Shrs * Everything's set up now: 229224144Shrs * connection established (hardwired or dialup) 230224144Shrs * line conditioned (baud rate, mode, etc.) 231224144Shrs * internal data structures (variables) 232224144Shrs * so, fork one process for local side and one for remote. 233224144Shrs */ 234224144Shrs printf(cumode ? "Connected\r\n" : "\07connected\r\n"); 235224144Shrs tipin_pid = getpid(); 236224144Shrs if ((tipout_pid = fork())) 237224144Shrs tipin(); 238224144Shrs else 239224144Shrs tipout(); 240224144Shrs exit(0); 241224144Shrs} 242224144Shrs 243224144Shrsvoid 244224144Shrscleanup(int signo) 245224144Shrs{ 246224144Shrs daemon_uid(); 247224144Shrs (void)uu_unlock(uucplock); 248224144Shrs if (odisc) 249224144Shrs ioctl(0, TIOCSETD, &odisc); 250224144Shrs unraw(); 251224144Shrs if (signo && tipout_pid) { 252224144Shrs kill(tipout_pid, signo); 253224144Shrs wait(NULL); 254224144Shrs } 255224144Shrs exit(0); 256224144Shrs} 257224144Shrs 258224144Shrs/* 259224144Shrs * Muck with user ID's. We are setuid to the owner of the lock 260224144Shrs * directory when we start. user_uid() reverses real and effective 261224144Shrs * ID's after startup, to run with the user's permissions. 262224144Shrs * daemon_uid() switches back to the privileged uid for unlocking. 263224144Shrs * Finally, to avoid running a shell with the wrong real uid, 264224144Shrs * shell_uid() sets real and effective uid's to the user's real ID. 265224144Shrs */ 266224144Shrsstatic int uidswapped; 267224144Shrs 268224144Shrsvoid 269224144Shrsuser_uid(void) 270224144Shrs{ 271224144Shrs if (uidswapped == 0) { 272224144Shrs seteuid(uid); 273224144Shrs uidswapped = 1; 274224144Shrs } 275224144Shrs} 276222972Shrs 277222972Shrsvoid 278222972Shrsdaemon_uid(void) 279222972Shrs{ 280224144Shrs 281222732Shrs if (uidswapped) { 282222732Shrs seteuid(euid); 283222732Shrs uidswapped = 0; 284222732Shrs } 285222732Shrs} 286222732Shrs 287222732Shrsvoid 288222732Shrsshell_uid(void) 289224144Shrs{ 290222732Shrs setegid(gid); 291222732Shrs seteuid(uid); 292224144Shrs} 293224144Shrs 294224144Shrs/* 295222732Shrs * put the controlling keyboard into raw mode 296222732Shrs */ 297222732Shrsvoid 298222732Shrsraw(void) 299254955Shrs{ 300254955Shrs tcsetattr(0, TCSADRAIN, &term); 301222732Shrs} 302222732Shrs 303222732Shrs 304222732Shrs/* 305222732Shrs * return keyboard to normal mode 306222732Shrs */ 307222732Shrsvoid 308222732Shrsunraw(void) 309222732Shrs{ 310222732Shrs if (gotdefterm) 311222732Shrs tcsetattr(0, TCSADRAIN, &defterm); 312222732Shrs} 313222732Shrs 314222732Shrs/* 315222732Shrs * give up exclusive tty access 316222732Shrs */ 317222732Shrsvoid 318222732Shrsunexcl() 319222732Shrs{ 320222732Shrs ioctl(FD, TIOCNXCL, 0); 321222732Shrs} 322224144Shrs 323224144Shrsstatic jmp_buf promptbuf; 324222732Shrs 325222732Shrs/* 326222732Shrs * Print string ``s'', then read a string 327224144Shrs * in from the terminal. Handles signals & allows use of 328224144Shrs * normal erase and kill characters. 329222732Shrs */ 330222732Shrsint 331224144Shrsprompt(char *s, char *p, size_t sz) 332222732Shrs{ 333222732Shrs int c; 334222972Shrs char *b = p; 335224144Shrs sig_t oint, oquit; 336222732Shrs 337222732Shrs stoprompt = 0; 338222732Shrs oint = signal(SIGINT, intprompt); 339222732Shrs oquit = signal(SIGQUIT, SIG_IGN); 340222732Shrs unraw(); 341224144Shrs printf("%s", s); 342224144Shrs if (setjmp(promptbuf) == 0) 343224144Shrs while ((c = getchar()) != EOF && (*p = c) != '\n' && --sz > 0) 344224144Shrs p++; 345224144Shrs *p = '\0'; 346224144Shrs 347224144Shrs raw(); 348224144Shrs (void)signal(SIGINT, oint); 349222732Shrs (void)signal(SIGQUIT, oquit); 350222732Shrs return (stoprompt || p == b); 351224144Shrs} 35255505Sshin 35355505Sshin/* 354222732Shrs * Interrupt service routine during prompting 355222732Shrs */ 356222732Shrs/*ARGSUSED*/ 357224144Shrsstatic void 35855505Sshinintprompt(int signo) 35955505Sshin{ 360222820Shrs (void)signal(SIGINT, SIG_IGN); 361222732Shrs stoprompt = 1; 362222732Shrs printf("\r\n"); 363222732Shrs longjmp(promptbuf, 1); 364222732Shrs} 365222732Shrs 366224144Shrs/* 36755505Sshin * ****TIPIN TIPIN**** 368222732Shrs */ 369222732Shrsstatic void 370222732Shrstipin(void) 371222732Shrs{ 372222732Shrs int bol = 1; 37378064Sume int gch; 37455505Sshin char ch; 37555505Sshin 376222732Shrs /* 37755505Sshin * Kinda klugey here... 378222732Shrs * check for scripting being turned on from the .tiprc file, 379222732Shrs * but be careful about just using setscript(), as we may 380224144Shrs * send a SIGEMT before tipout has a chance to set up catching 38155505Sshin * it; so wait a second, then setscript() 382222732Shrs */ 383224144Shrs if (boolean(value(SCRIPT))) { 384222972Shrs sleep(1); 38555505Sshin setscript(); 38655505Sshin } 38755505Sshin 38855505Sshin while (1) { 38955505Sshin gch = getchar(); 39055505Sshin if (gch == EOF) 39155505Sshin return; 39255505Sshin gch = gch & STRIP_PAR; 39355505Sshin if ((gch == character(value(ESCAPE))) && bol) { 394224144Shrs if (!noesc) { 395222732Shrs gch = escape(); 396224144Shrs if (gch == EOF) 397222972Shrs return; 39855505Sshin if (gch == 0) 399224144Shrs continue; 400222732Shrs } 401222732Shrs } else if (!cumode && gch == character(value(RAISECHAR))) { 402224144Shrs setboolean(value(RAISE), !boolean(value(RAISE))); 403224144Shrs continue; 40455505Sshin } else if (gch == '\r') { 405224144Shrs bol = 1; 406222732Shrs ch = gch; 407224144Shrs parwrite(FD, &ch, 1); 408222732Shrs if (boolean(value(HALFDUPLEX))) 409222972Shrs printf("\r\n"); 41055505Sshin continue; 411224144Shrs } else if (!cumode && gch == character(value(FORCE))) { 41255505Sshin gch = getchar(); 41355505Sshin if (gch == EOF) 414222732Shrs return; 41555505Sshin gch = gch & STRIP_PAR; 416118968Sume } 417118968Sume bol = any(gch, value(EOL)); 418118968Sume if (boolean(value(RAISE)) && islower(gch)) 419118968Sume gch = toupper(gch); 420118968Sume ch = gch; 421118968Sume parwrite(FD, &ch, 1); 422118968Sume if (boolean(value(HALFDUPLEX))) 423118968Sume printf("%c", ch); 424118968Sume } 425118968Sume} 426118968Sume 427118968Sumeextern esctable_t etable[]; 428222972Shrs 429118968Sume/* 430118968Sume * Escape handler -- 431118968Sume * called on recognition of ``escapec'' at the beginning of a line 432222732Shrs */ 433118968Sumestatic int 434222732Shrsescape(void) 435222732Shrs{ 436222732Shrs int gch; 43778064Sume esctable_t *p; 43878064Sume char c = character(value(ESCAPE)); 43978064Sume 44078064Sume gch = getchar(); 441222732Shrs if (gch == EOF) 442222732Shrs return (EOF); 443118968Sume gch = gch & STRIP_PAR; 444224144Shrs for (p = etable; p->e_char; p++) 445222972Shrs if (p->e_char == gch) { 44678064Sume if ((p->e_flags&PRIV) && uid) 44755505Sshin continue; 448222732Shrs printf("%s", ctrl(c)); 449224144Shrs (*p->e_func)(gch); 450224144Shrs return (0); 45155505Sshin } 452224144Shrs /* ESCAPE ESCAPE forces ESCAPE */ 453222732Shrs if (c != gch) 454224144Shrs parwrite(FD, &c, 1); 455222732Shrs return (gch); 456222972Shrs} 45755505Sshin 458222732Shrsint 45955505Sshinany(int cc, char *p) 46055505Sshin{ 461118968Sume char c = cc; 46255505Sshin while (p && *p) 463224144Shrs if (*p++ == c) 464222732Shrs return (1); 465224144Shrs return (0); 466222972Shrs} 46755505Sshin 468224144Shrssize_t 46955505Sshinsize(char *s) 47078064Sume{ 47178064Sume size_t i = 0; 472224144Shrs 473224144Shrs while (s && *s++) 474222972Shrs i++; 47555505Sshin return (i); 476224144Shrs} 47755505Sshin 478118968Sumechar * 47978064Sumeinterp(char *s) 480222732Shrs{ 481222732Shrs static char buf[256]; 482222972Shrs char *p = buf, c, *q; 48378064Sume 48455505Sshin while ((c = *s++)) { 48578064Sume for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++) 48678064Sume if (*q++ == c) { 487118664Sume *p++ = '\\'; *p++ = *q; 48878064Sume goto next; 48978064Sume } 49078064Sume if (c < 040) { 49178064Sume *p++ = '^'; *p++ = c + 'A'-1; 492222732Shrs } else if (c == 0177) { 49378064Sume *p++ = '^'; *p++ = '?'; 494222732Shrs } else 495118968Sume *p++ = c; 496118968Sume next: 497118968Sume ; 498118968Sume } 499118968Sume *p = '\0'; 500118968Sume return (buf); 501118968Sume} 502118968Sume 503118968Sumechar * 504222732Shrsctrl(char c) 505222820Shrs{ 506222732Shrs static char s[3]; 50771437Sume 508222732Shrs if (c < 040 || c == 0177) { 509118968Sume s[0] = '^'; 510222732Shrs s[1] = c == 0177 ? '?' : c+'A'-1; 511222732Shrs s[2] = '\0'; 512222972Shrs } else { 513118968Sume s[0] = c; 514222732Shrs s[1] = '\0'; 515118968Sume } 516222732Shrs return (s); 517222732Shrs} 518224144Shrs 519222972Shrs/* 520118968Sume * Help command 521222732Shrs */ 522118968Sumevoid 523222732Shrshelp(int c) 524222732Shrs{ 525224144Shrs esctable_t *p; 52662656Skris 527118968Sume printf("%c\r\n", c); 528118968Sume for (p = etable; p->e_char; p++) { 529118968Sume if ((p->e_flags&PRIV) && uid) 530224144Shrs continue; 531222732Shrs printf("%2s", ctrl(character(value(ESCAPE)))); 532224144Shrs printf("%-2s %c %s\r\n", ctrl(p->e_char), 533222972Shrs p->e_flags&EXP ? '*': ' ', p->e_help); 534118968Sume } 535222732Shrs} 53655505Sshin 537118968Sume/* 538118968Sume * Set up the "remote" tty's state 539118968Sume */ 540118968Sumeint 541118968Sumettysetup(int speed) 542118968Sume{ 543118968Sume struct termios cntrl; 544118968Sume 545118968Sume if (tcgetattr(FD, &cntrl)) 546118968Sume return (-1); 547118968Sume cfsetspeed(&cntrl, speed); 548222732Shrs cntrl.c_cflag &= ~(CSIZE|PARENB); 549222732Shrs cntrl.c_cflag |= CS8; 55055505Sshin if (boolean(value(DC))) 551118968Sume cntrl.c_cflag |= CLOCAL; 552118968Sume if (boolean(value(HARDWAREFLOW))) 553118968Sume cntrl.c_cflag |= CRTSCTS; 554224144Shrs cntrl.c_iflag &= ~(ISTRIP|ICRNL); 555118968Sume cntrl.c_oflag &= ~OPOST; 556224144Shrs cntrl.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO); 557224144Shrs cntrl.c_cc[VMIN] = 1; 558222972Shrs cntrl.c_cc[VTIME] = 0; 559118968Sume if (boolean(value(TAND))) 560224144Shrs cntrl.c_iflag |= IXOFF; 56155505Sshin return (tcsetattr(FD, TCSAFLUSH, &cntrl)); 562118968Sume} 563118968Sume 564253970Shrsstatic char partab[0200]; 565253970Shrs 566253970Shrs/* 567222732Shrs * Do a write to the remote machine with the correct parity. 568222732Shrs * We are doing 8 bit wide output, so we just generate a character 569118968Sume * with the right parity and output it. 57078064Sume */ 571118968Sumevoid 572118968Sumeparwrite(int fd, char *buf, size_t n) 573118968Sume{ 574118968Sume size_t i; 575224144Shrs char *bp; 576118968Sume 577224144Shrs bp = buf; 578224144Shrs if (bits8 == 0) 579222972Shrs for (i = 0; i < n; i++) { 580118968Sume *bp = partab[(*bp) & 0177]; 581224144Shrs bp++; 58255505Sshin } 583118968Sume if (write(fd, buf, n) < 0) { 584118968Sume if (errno == EIO || errno == ENXIO) 585253970Shrs tipabort("Lost carrier."); 586253970Shrs /* this is questionable */ 587253970Shrs perror("write"); 588222732Shrs } 589222732Shrs} 59055505Sshin 591222820Shrs/* 592222820Shrs * Build a parity table with appropriate high-order bit. 593222820Shrs */ 594222972Shrsvoid 595222972Shrssetparity(char *defparity) 596222972Shrs{ 59755505Sshin int i, flip, clr, set; 598222732Shrs char *parity; 599222732Shrs extern const unsigned char evenpartab[]; 60055505Sshin 601224144Shrs if (value(PARITY) == NOSTR) 602224144Shrs value(PARITY) = defparity; 60355505Sshin parity = value(PARITY); 604224144Shrs if (equal(parity, "none")) { 605224144Shrs bits8 = 1; 606222972Shrs return; 60755505Sshin } 608224144Shrs bits8 = 0; 609222732Shrs flip = 0; 61055505Sshin clr = 0377; 61155505Sshin set = 0; 61255505Sshin if (equal(parity, "odd")) 61355505Sshin flip = 0200; /* reverse bit 7 */ 614224144Shrs else if (equal(parity, "zero")) 61555505Sshin clr = 0177; /* turn off bit 7 */ 616222732Shrs else if (equal(parity, "one")) 617224144Shrs set = 0200; /* turn on bit 7 */ 61855505Sshin else if (!equal(parity, "even")) { 619224144Shrs (void) fprintf(stderr, "%s: unknown parity value\r\n", parity); 620222732Shrs (void) fflush(stderr); 621224144Shrs } 622224144Shrs for (i = 0; i < 0200; i++) 623222972Shrs partab[i] = ((evenpartab[i] ^ flip) | set) & clr; 62455505Sshin} 62555505Sshin