xref: /csrg-svn/usr.bin/tip/tip.c (revision 46261)
119806Sdist /*
235464Sbostic  * Copyright (c) 1983 The Regents of the University of California.
335464Sbostic  * All rights reserved.
435464Sbostic  *
542770Sbostic  * %sccs.include.redist.c%
619806Sdist  */
719806Sdist 
813279Ssam #ifndef lint
919806Sdist char copyright[] =
1035464Sbostic "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
1119806Sdist  All rights reserved.\n";
1235464Sbostic #endif /* not lint */
135136Ssam 
1419806Sdist #ifndef lint
15*46261Storek static char sccsid[] = "@(#)tip.c	5.15 (Berkeley) 02/04/91";
1635464Sbostic #endif /* not lint */
1719806Sdist 
183696Sroot /*
195136Ssam  * tip - UNIX link to other systems
203696Sroot  *  tip [-v] [-speed] system-name
215136Ssam  * or
225136Ssam  *  cu phone-number [-s speed] [-l line] [-a acu]
233696Sroot  */
243696Sroot #include "tip.h"
2537857Sbostic #include "pathnames.h"
263696Sroot 
273696Sroot /*
283696Sroot  * Baud rate mapping table
293696Sroot  */
303696Sroot int bauds[] = {
313696Sroot 	0, 50, 75, 110, 134, 150, 200, 300, 600,
323696Sroot 	1200, 1800, 2400, 4800, 9600, 19200, -1
333696Sroot };
343696Sroot 
354004Ssam int	disc = OTTYDISC;		/* tip normally runs this way */
3639254Sbostic void	intprompt();
3739254Sbostic void	timeout();
3839254Sbostic void	cleanup();
395257Sshannon char	*sname();
4025550Sdonn char	PNbuf[256];			/* This limits the size of a number */
413696Sroot 
423696Sroot main(argc, argv)
434962Ssam 	char *argv[];
443696Sroot {
453696Sroot 	char *system = NOSTR;
463696Sroot 	register int i;
475257Sshannon 	register char *p;
485257Sshannon 	char sbuf[12];
493696Sroot 
5030458Skarels 	gid = getgid();
5130458Skarels 	egid = getegid();
5230458Skarels 	uid = getuid();
5330458Skarels 	euid = geteuid();
545257Sshannon 	if (equal(sname(argv[0]), "cu")) {
5525905Skarels 		cumode = 1;
565136Ssam 		cumain(argc, argv);
575136Ssam 		goto cucommon;
585136Ssam 	}
595136Ssam 
603696Sroot 	if (argc > 4) {
613696Sroot 		fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n");
623696Sroot 		exit(1);
633696Sroot 	}
643696Sroot 	if (!isatty(0)) {
653696Sroot 		fprintf(stderr, "tip: must be interactive\n");
663696Sroot 		exit(1);
673696Sroot 	}
685257Sshannon 
695257Sshannon 	for (; argc > 1; argv++, argc--) {
705257Sshannon 		if (argv[1][0] != '-')
715257Sshannon 			system = argv[1];
725257Sshannon 		else switch (argv[1][1]) {
735257Sshannon 
745257Sshannon 		case 'v':
755257Sshannon 			vflag++;
765257Sshannon 			break;
775257Sshannon 
785257Sshannon 		case '0': case '1': case '2': case '3': case '4':
795257Sshannon 		case '5': case '6': case '7': case '8': case '9':
805257Sshannon 			BR = atoi(&argv[1][1]);
815257Sshannon 			break;
825257Sshannon 
835257Sshannon 		default:
845257Sshannon 			fprintf(stderr, "tip: %s, unknown option\n", argv[1]);
855257Sshannon 			break;
865257Sshannon 		}
875257Sshannon 	}
885257Sshannon 
897593Sshannon 	if (system == NOSTR)
907593Sshannon 		goto notnumber;
9127004Sdonn 	if (isalpha(*system))
9227004Sdonn 		goto notnumber;
9325550Sdonn 	/*
9425550Sdonn 	 * System name is really a phone number...
9525550Sdonn 	 * Copy the number then stomp on the original (in case the number
9625550Sdonn 	 *	is private, we don't want 'ps' or 'w' to find it).
9725550Sdonn 	 */
9825550Sdonn 	if (strlen(system) > sizeof PNbuf - 1) {
9925550Sdonn 		fprintf(stderr, "tip: phone number too long (max = %d bytes)\n",
10025550Sdonn 			sizeof PNbuf - 1);
10125550Sdonn 		exit(1);
10225550Sdonn 	}
10325550Sdonn 	strncpy( PNbuf, system, sizeof PNbuf - 1 );
10425550Sdonn 	for (p = system; *p; p++)
10525550Sdonn 		*p = '\0';
10625550Sdonn 	PN = PNbuf;
10732513Sbostic 	(void)sprintf(sbuf, "tip%d", BR);
10832513Sbostic 	system = sbuf;
1095257Sshannon 
1105257Sshannon notnumber:
11140695Sbostic 	(void)signal(SIGINT, cleanup);
11240695Sbostic 	(void)signal(SIGQUIT, cleanup);
11340695Sbostic 	(void)signal(SIGHUP, cleanup);
11440695Sbostic 	(void)signal(SIGTERM, cleanup);
1153898Ssam 
1163696Sroot 	if ((i = hunt(system)) == 0) {
1173696Sroot 		printf("all ports busy\n");
1183696Sroot 		exit(3);
1193696Sroot 	}
1203696Sroot 	if (i == -1) {
1213696Sroot 		printf("link down\n");
12235460Sbostic 		(void)uu_unlock(uucplock);
1233696Sroot 		exit(3);
1243696Sroot 	}
1253719Ssam 	setbuf(stdout, NULL);
1263696Sroot 	loginit();
1275257Sshannon 
1283696Sroot 	/*
1293696Sroot 	 * Kludge, their's no easy way to get the initialization
1303696Sroot 	 *   in the right order, so force it here
1313696Sroot 	 */
1323696Sroot 	if ((PH = getenv("PHONES")) == NOSTR)
13337857Sbostic 		PH = _PATH_PHONES;
1343696Sroot 	vinit();				/* init variables */
13513430Ssam 	setparity("even");			/* set the parity table */
1364004Ssam 	if ((i = speed(number(value(BAUDRATE)))) == NULL) {
1373696Sroot 		printf("tip: bad baud rate %d\n", number(value(BAUDRATE)));
13835460Sbostic 		(void)uu_unlock(uucplock);
1393696Sroot 		exit(3);
1403696Sroot 	}
1413898Ssam 
1424004Ssam 	/*
14325905Skarels 	 * Now that we have the logfile and the ACU open
14425905Skarels 	 *  return to the real uid and gid.  These things will
14525905Skarels 	 *  be closed on exit.  Swap real and effective uid's
14625905Skarels 	 *  so we can get the original permissions back
14725905Skarels 	 *  for removing the uucp lock.
14825905Skarels 	 */
14930458Skarels 	user_uid();
15025905Skarels 
15125905Skarels 	/*
1524004Ssam 	 * Hardwired connections require the
1534004Ssam 	 *  line speed set before they make any transmissions
1544004Ssam 	 *  (this is particularly true of things like a DF03-AC)
1554004Ssam 	 */
1564004Ssam 	if (HW)
1574004Ssam 		ttysetup(i);
1583898Ssam 	if (p = connect()) {
1593898Ssam 		printf("\07%s\n[EOT]\n", p);
16030458Skarels 		daemon_uid();
16135460Sbostic 		(void)uu_unlock(uucplock);
1623898Ssam 		exit(1);
1633898Ssam 	}
1644004Ssam 	if (!HW)
1654004Ssam 		ttysetup(i);
1665136Ssam cucommon:
1673696Sroot 	/*
1685136Ssam 	 * From here down the code is shared with
1695136Ssam 	 * the "cu" version of tip.
1703696Sroot 	 */
17125905Skarels 
1724004Ssam 	ioctl(0, TIOCGETP, (char *)&defarg);
1734004Ssam 	ioctl(0, TIOCGETC, (char *)&defchars);
17412478Sroot 	ioctl(0, TIOCGLTC, (char *)&deflchars);
1754004Ssam 	ioctl(0, TIOCGETD, (char *)&odisc);
1763696Sroot 	arg = defarg;
1773696Sroot 	arg.sg_flags = ANYP | CBREAK;
1783696Sroot 	tchars = defchars;
1793696Sroot 	tchars.t_intrc = tchars.t_quitc = -1;
18012478Sroot 	ltchars = deflchars;
18112478Sroot 	ltchars.t_suspc = ltchars.t_dsuspc = ltchars.t_flushc
18212478Sroot 		= ltchars.t_lnextc = -1;
1833696Sroot 	raw();
1844004Ssam 
1853696Sroot 	pipe(fildes); pipe(repdes);
18640695Sbostic 	(void)signal(SIGALRM, timeout);
1873898Ssam 
1883898Ssam 	/*
1893898Ssam 	 * Everything's set up now:
19017236Shelge 	 *	connection established (hardwired or dialup)
1913898Ssam 	 *	line conditioned (baud rate, mode, etc.)
1923898Ssam 	 *	internal data structures (variables)
1933898Ssam 	 * so, fork one process for local side and one for remote.
1943898Ssam 	 */
1955136Ssam 	printf(cumode ? "Connected\r\n" : "\07connected\r\n");
1963696Sroot 	if (pid = fork())
1973696Sroot 		tipin();
1983696Sroot 	else
1993696Sroot 		tipout();
2003696Sroot 	/*NOTREACHED*/
2013696Sroot }
2023696Sroot 
20339254Sbostic void
2043696Sroot cleanup()
2053696Sroot {
20613279Ssam 
20730458Skarels 	daemon_uid();
20835460Sbostic 	(void)uu_unlock(uucplock);
2093898Ssam 	if (odisc)
2103898Ssam 		ioctl(0, TIOCSETD, (char *)&odisc);
2113696Sroot 	exit(0);
2123696Sroot }
2133696Sroot 
2143696Sroot /*
21530458Skarels  * Muck with user ID's.  We are setuid to the owner of the lock
21630458Skarels  * directory when we start.  user_uid() reverses real and effective
21730458Skarels  * ID's after startup, to run with the user's permissions.
21830458Skarels  * daemon_uid() switches back to the privileged uid for unlocking.
21930458Skarels  * Finally, to avoid running a shell with the wrong real uid,
22030458Skarels  * shell_uid() sets real and effective uid's to the user's real ID.
22130458Skarels  */
22230458Skarels static int uidswapped;
22330458Skarels 
22430458Skarels user_uid()
22530458Skarels {
22630458Skarels 	if (uidswapped == 0) {
22730458Skarels 		setregid(egid, gid);
22830458Skarels 		setreuid(euid, uid);
22930458Skarels 		uidswapped = 1;
23030458Skarels 	}
23130458Skarels }
23230458Skarels 
23330458Skarels daemon_uid()
23430458Skarels {
23530458Skarels 
23630458Skarels 	if (uidswapped) {
23730458Skarels 		setreuid(uid, euid);
23830458Skarels 		setregid(gid, egid);
23930458Skarels 		uidswapped = 0;
24030458Skarels 	}
24130458Skarels }
24230458Skarels 
24330458Skarels shell_uid()
24430458Skarels {
24530458Skarels 
24630458Skarels 	setreuid(uid, uid);
24730458Skarels 	setregid(gid, gid);
24830458Skarels }
24930458Skarels 
25030458Skarels /*
2513696Sroot  * put the controlling keyboard into raw mode
2523696Sroot  */
2533696Sroot raw()
2543696Sroot {
25513279Ssam 
2563696Sroot 	ioctl(0, TIOCSETP, &arg);
2573696Sroot 	ioctl(0, TIOCSETC, &tchars);
25812478Sroot 	ioctl(0, TIOCSLTC, &ltchars);
2594004Ssam 	ioctl(0, TIOCSETD, (char *)&disc);
2603696Sroot }
2613696Sroot 
2623696Sroot 
2633696Sroot /*
2643696Sroot  * return keyboard to normal mode
2653696Sroot  */
2663696Sroot unraw()
2673696Sroot {
26813279Ssam 
2694004Ssam 	ioctl(0, TIOCSETD, (char *)&odisc);
2704004Ssam 	ioctl(0, TIOCSETP, (char *)&defarg);
2714004Ssam 	ioctl(0, TIOCSETC, (char *)&defchars);
27212478Sroot 	ioctl(0, TIOCSLTC, (char *)&deflchars);
2733696Sroot }
2743696Sroot 
27513279Ssam static	jmp_buf promptbuf;
27613279Ssam 
2773696Sroot /*
2783696Sroot  * Print string ``s'', then read a string
2793696Sroot  *  in from the terminal.  Handles signals & allows use of
2803696Sroot  *  normal erase and kill characters.
2813696Sroot  */
2823696Sroot prompt(s, p)
2833696Sroot 	char *s;
2843696Sroot 	register char *p;
2853696Sroot {
2863696Sroot 	register char *b = p;
28739254Sbostic 	sig_t oint, oquit;
2883696Sroot 
2893696Sroot 	stoprompt = 0;
29013279Ssam 	oint = signal(SIGINT, intprompt);
29140695Sbostic 	oquit = signal(SIGQUIT, SIG_IGN);
2923696Sroot 	unraw();
2933696Sroot 	printf("%s", s);
29413279Ssam 	if (setjmp(promptbuf) == 0)
29513279Ssam 		while ((*p = getchar()) != EOF && *p != '\n')
29613279Ssam 			p++;
2973696Sroot 	*p = '\0';
29813279Ssam 
2993696Sroot 	raw();
30040695Sbostic 	(void)signal(SIGINT, oint);
30140695Sbostic 	(void)signal(SIGQUIT, oquit);
30213279Ssam 	return (stoprompt || p == b);
3033696Sroot }
3043696Sroot 
3053696Sroot /*
3063696Sroot  * Interrupt service routine during prompting
3073696Sroot  */
30839254Sbostic void
3093696Sroot intprompt()
3103696Sroot {
31113279Ssam 
31240695Sbostic 	(void)signal(SIGINT, SIG_IGN);
3133696Sroot 	stoprompt = 1;
3143696Sroot 	printf("\r\n");
31513279Ssam 	longjmp(promptbuf, 1);
3163696Sroot }
3173696Sroot 
3183696Sroot /*
3193696Sroot  * ****TIPIN   TIPIN****
3203696Sroot  */
3213696Sroot tipin()
3223696Sroot {
3233696Sroot 	char gch, bol = 1;
3243696Sroot 
3253796Ssam 	/*
3263796Ssam 	 * Kinda klugey here...
3273796Ssam 	 *   check for scripting being turned on from the .tiprc file,
3283796Ssam 	 *   but be careful about just using setscript(), as we may
3293796Ssam 	 *   send a SIGEMT before tipout has a chance to set up catching
3303796Ssam 	 *   it; so wait a second, then setscript()
3313796Ssam 	 */
3323796Ssam 	if (boolean(value(SCRIPT))) {
3333796Ssam 		sleep(1);
3343796Ssam 		setscript();
3353796Ssam 	}
3363796Ssam 
3373696Sroot 	while (1) {
3383696Sroot 		gch = getchar()&0177;
3393696Sroot 		if ((gch == character(value(ESCAPE))) && bol) {
3403696Sroot 			if (!(gch = escape()))
3413696Sroot 				continue;
3425136Ssam 		} else if (!cumode && gch == character(value(RAISECHAR))) {
3433696Sroot 			boolean(value(RAISE)) = !boolean(value(RAISE));
3443696Sroot 			continue;
3453696Sroot 		} else if (gch == '\r') {
3463696Sroot 			bol = 1;
34713139Sralph 			pwrite(FD, &gch, 1);
34813139Sralph 			if (boolean(value(HALFDUPLEX)))
34913139Sralph 				printf("\r\n");
3503696Sroot 			continue;
3515136Ssam 		} else if (!cumode && gch == character(value(FORCE)))
3523696Sroot 			gch = getchar()&0177;
3533696Sroot 		bol = any(gch, value(EOL));
3543696Sroot 		if (boolean(value(RAISE)) && islower(gch))
35513139Sralph 			gch = toupper(gch);
35613139Sralph 		pwrite(FD, &gch, 1);
35713139Sralph 		if (boolean(value(HALFDUPLEX)))
35813139Sralph 			printf("%c", gch);
3593696Sroot 	}
3603696Sroot }
3613696Sroot 
3623696Sroot /*
3633696Sroot  * Escape handler --
3643696Sroot  *  called on recognition of ``escapec'' at the beginning of a line
3653696Sroot  */
3663696Sroot escape()
3673696Sroot {
3683696Sroot 	register char gch;
3693696Sroot 	register esctable_t *p;
3703696Sroot 	char c = character(value(ESCAPE));
3713696Sroot 	extern esctable_t etable[];
3723696Sroot 
3733696Sroot 	gch = (getchar()&0177);
3743696Sroot 	for (p = etable; p->e_char; p++)
3753696Sroot 		if (p->e_char == gch) {
37630458Skarels 			if ((p->e_flags&PRIV) && uid)
3773696Sroot 				continue;
3783696Sroot 			printf("%s", ctrl(c));
3793696Sroot 			(*p->e_func)(gch);
38013279Ssam 			return (0);
3813696Sroot 		}
3824146Ssam 	/* ESCAPE ESCAPE forces ESCAPE */
3834146Ssam 	if (c != gch)
38413139Sralph 		pwrite(FD, &c, 1);
38513279Ssam 	return (gch);
3863696Sroot }
3873696Sroot 
3883696Sroot speed(n)
38913279Ssam 	int n;
3903696Sroot {
3913696Sroot 	register int *p;
3923696Sroot 
3933696Sroot 	for (p = bauds; *p != -1;  p++)
3943696Sroot 		if (*p == n)
39513279Ssam 			return (p - bauds);
39613279Ssam 	return (NULL);
3973696Sroot }
3983696Sroot 
3993696Sroot any(c, p)
4003696Sroot 	register char c, *p;
4013696Sroot {
40213279Ssam 	while (p && *p)
4033696Sroot 		if (*p++ == c)
40413279Ssam 			return (1);
40513279Ssam 	return (0);
4063696Sroot }
4073696Sroot 
4083696Sroot size(s)
4093696Sroot 	register char	*s;
4103696Sroot {
41113279Ssam 	register int i = 0;
4123696Sroot 
41313279Ssam 	while (s && *s++)
41413279Ssam 		i++;
41513279Ssam 	return (i);
4163696Sroot }
4173696Sroot 
4183696Sroot char *
4193696Sroot interp(s)
4203696Sroot 	register char *s;
4213696Sroot {
4223696Sroot 	static char buf[256];
4233696Sroot 	register char *p = buf, c, *q;
4243696Sroot 
4253696Sroot 	while (c = *s++) {
4263696Sroot 		for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++)
4273696Sroot 			if (*q++ == c) {
4283696Sroot 				*p++ = '\\'; *p++ = *q;
4293696Sroot 				goto next;
4303696Sroot 			}
4313696Sroot 		if (c < 040) {
4323696Sroot 			*p++ = '^'; *p++ = c + 'A'-1;
4333696Sroot 		} else if (c == 0177) {
4343696Sroot 			*p++ = '^'; *p++ = '?';
4353696Sroot 		} else
4363696Sroot 			*p++ = c;
4373696Sroot 	next:
4383696Sroot 		;
4393696Sroot 	}
4403696Sroot 	*p = '\0';
44113279Ssam 	return (buf);
4423696Sroot }
4433696Sroot 
4443696Sroot char *
4453696Sroot ctrl(c)
4463696Sroot 	char c;
4473696Sroot {
4483696Sroot 	static char s[3];
4493696Sroot 
4503696Sroot 	if (c < 040 || c == 0177) {
4513696Sroot 		s[0] = '^';
4523696Sroot 		s[1] = c == 0177 ? '?' : c+'A'-1;
4533696Sroot 		s[2] = '\0';
4543696Sroot 	} else {
4553696Sroot 		s[0] = c;
4563696Sroot 		s[1] = '\0';
4573696Sroot 	}
45813279Ssam 	return (s);
4593696Sroot }
4603696Sroot 
4613696Sroot /*
4623696Sroot  * Help command
4633696Sroot  */
4643696Sroot help(c)
4653696Sroot 	char c;
4663696Sroot {
4673696Sroot 	register esctable_t *p;
4683696Sroot 	extern esctable_t etable[];
4693696Sroot 
4703696Sroot 	printf("%c\r\n", c);
4713696Sroot 	for (p = etable; p->e_char; p++) {
47230458Skarels 		if ((p->e_flags&PRIV) && uid)
4733696Sroot 			continue;
4743696Sroot 		printf("%2s", ctrl(character(value(ESCAPE))));
4753696Sroot 		printf("%-2s %c   %s\r\n", ctrl(p->e_char),
4763696Sroot 			p->e_flags&EXP ? '*': ' ', p->e_help);
4773696Sroot 	}
4783696Sroot }
4794004Ssam 
4804004Ssam /*
4814004Ssam  * Set up the "remote" tty's state
4824004Ssam  */
4834004Ssam ttysetup(speed)
48413279Ssam 	int speed;
4854004Ssam {
4864004Ssam 	unsigned bits = LDECCTQ;
4874004Ssam 
4884004Ssam 	arg.sg_ispeed = arg.sg_ospeed = speed;
48913279Ssam 	arg.sg_flags = RAW;
49013139Sralph 	if (boolean(value(TAND)))
49113279Ssam 		arg.sg_flags |= TANDEM;
4924004Ssam 	ioctl(FD, TIOCSETP, (char *)&arg);
4934004Ssam 	ioctl(FD, TIOCLBIS, (char *)&bits);
4944004Ssam }
4955257Sshannon 
4965257Sshannon /*
4975257Sshannon  * Return "simple" name from a file name,
4985257Sshannon  * strip leading directories.
4995257Sshannon  */
5005257Sshannon char *
5015257Sshannon sname(s)
5025257Sshannon 	register char *s;
5035257Sshannon {
5045257Sshannon 	register char *p = s;
5055257Sshannon 
5065257Sshannon 	while (*s)
5075257Sshannon 		if (*s++ == '/')
5085257Sshannon 			p = s;
5095257Sshannon 	return (p);
5105257Sshannon }
51113139Sralph 
51213139Sralph static char partab[0200];
51340240Skarels static int bits8;
51413139Sralph 
51513139Sralph /*
51613279Ssam  * Do a write to the remote machine with the correct parity.
51713279Ssam  * We are doing 8 bit wide output, so we just generate a character
51813139Sralph  * with the right parity and output it.
51913139Sralph  */
52013139Sralph pwrite(fd, buf, n)
52113139Sralph 	int fd;
52213139Sralph 	char *buf;
52313139Sralph 	register int n;
52413139Sralph {
52513139Sralph 	register int i;
52613279Ssam 	register char *bp;
52715188Ssam 	extern int errno;
52813139Sralph 
52913279Ssam 	bp = buf;
53040240Skarels 	if (bits8 == 0)
53140240Skarels 		for (i = 0; i < n; i++) {
53240240Skarels 			*bp = partab[(*bp) & 0177];
53340240Skarels 			bp++;
53440240Skarels 		}
53515188Ssam 	if (write(fd, buf, n) < 0) {
53615188Ssam 		if (errno == EIO)
537*46261Storek 			tipabort("Lost carrier.");
53815188Ssam 		/* this is questionable */
53915188Ssam 		perror("write");
54015188Ssam 	}
54113139Sralph }
54213139Sralph 
54313139Sralph /*
54413279Ssam  * Build a parity table with appropriate high-order bit.
54513139Sralph  */
54613430Ssam setparity(defparity)
54713430Ssam 	char *defparity;
54813139Sralph {
549*46261Storek 	register int i, flip, clr, set;
55013139Sralph 	char *parity;
55113279Ssam 	extern char evenpartab[];
55213139Sralph 
55313139Sralph 	if (value(PARITY) == NOSTR)
55413430Ssam 		value(PARITY) = defparity;
55513139Sralph 	parity = value(PARITY);
55640240Skarels 	if (equal(parity, "none")) {
55740240Skarels 		bits8 = 1;
55840240Skarels 		return;
55913139Sralph 	}
560*46261Storek 	bits8 = 0;
561*46261Storek 	flip = 0;
562*46261Storek 	clr = 0377;
563*46261Storek 	set = 0;
564*46261Storek 	if (equal(parity, "odd"))
565*46261Storek 		flip = 0200;			/* reverse bit 7 */
566*46261Storek 	else if (equal(parity, "zero"))
567*46261Storek 		clr = 0177;			/* turn off bit 7 */
568*46261Storek 	else if (equal(parity, "one"))
569*46261Storek 		set = 0200;			/* turn on bit 7 */
570*46261Storek 	else if (!equal(parity, "even")) {
571*46261Storek 		(void) fprintf(stderr, "%s: unknown parity value\r\n", parity);
572*46261Storek 		(void) fflush(stderr);
57313139Sralph 	}
574*46261Storek 	for (i = 0; i < 0200; i++)
575*46261Storek 		partab[i] = evenpartab[i] ^ flip | set & clr;
57613139Sralph }
577