1/*-
2 * Copyright (c) 1980, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#ifndef lint
31static const char copyright[] =
32"@(#) Copyright (c) 1980, 1993\n\
33	The Regents of the University of California.  All rights reserved.\n";
34#endif /* not lint */
35
36#ifndef lint
37#if 0
38static char sccsid[] = "@(#)from: main.c	8.1 (Berkeley) 6/20/93";
39#endif
40#endif /* not lint */
41#include <sys/cdefs.h>
42__FBSDID("$FreeBSD: stable/11/libexec/getty/main.c 323992 2017-09-25 20:04:14Z dab $");
43
44#include <sys/param.h>
45#include <sys/ioctl.h>
46#include <sys/time.h>
47#include <sys/resource.h>
48#include <sys/stat.h>
49#include <sys/ttydefaults.h>
50#include <sys/utsname.h>
51
52#include <ctype.h>
53#include <errno.h>
54#include <fcntl.h>
55#include <locale.h>
56#include <libutil.h>
57#include <setjmp.h>
58#include <signal.h>
59#include <stdlib.h>
60#include <string.h>
61#include <syslog.h>
62#include <termios.h>
63#include <time.h>
64#include <unistd.h>
65
66#include "gettytab.h"
67#include "extern.h"
68#include "pathnames.h"
69
70/*
71 * Set the amount of running time that getty should accumulate
72 * before deciding that something is wrong and exit.
73 */
74#define GETTY_TIMEOUT	60 /* seconds */
75
76#undef CTRL
77#define CTRL(x)  (x&037)
78
79/* defines for auto detection of incoming PPP calls (->PAP/CHAP) */
80
81#define PPP_FRAME           0x7e  /* PPP Framing character */
82#define PPP_STATION         0xff  /* "All Station" character */
83#define PPP_ESCAPE          0x7d  /* Escape Character */
84#define PPP_CONTROL         0x03  /* PPP Control Field */
85#define PPP_CONTROL_ESCAPED 0x23  /* PPP Control Field, escaped */
86#define PPP_LCP_HI          0xc0  /* LCP protocol - high byte */
87#define PPP_LCP_LOW         0x21  /* LCP protocol - low byte */
88
89/* original mode; flags've been reset using values from <sys/ttydefaults.h> */
90struct termios omode;
91/* current mode */
92struct termios tmode;
93
94int crmod, digit, lower, upper;
95
96char	hostname[MAXHOSTNAMELEN];
97char	name[MAXLOGNAME*3];
98char	dev[] = _PATH_DEV;
99char	ttyn[32];
100
101#define	OBUFSIZ		128
102#define	TABBUFSIZ	512
103
104char	defent[TABBUFSIZ];
105char	tabent[TABBUFSIZ];
106const	char *tname;
107
108char	*env[128];
109
110char partab[] = {
111	0001,0201,0201,0001,0201,0001,0001,0201,
112	0202,0004,0003,0205,0005,0206,0201,0001,
113	0201,0001,0001,0201,0001,0201,0201,0001,
114	0001,0201,0201,0001,0201,0001,0001,0201,
115	0200,0000,0000,0200,0000,0200,0200,0000,
116	0000,0200,0200,0000,0200,0000,0000,0200,
117	0000,0200,0200,0000,0200,0000,0000,0200,
118	0200,0000,0000,0200,0000,0200,0200,0000,
119	0200,0000,0000,0200,0000,0200,0200,0000,
120	0000,0200,0200,0000,0200,0000,0000,0200,
121	0000,0200,0200,0000,0200,0000,0000,0200,
122	0200,0000,0000,0200,0000,0200,0200,0000,
123	0000,0200,0200,0000,0200,0000,0000,0200,
124	0200,0000,0000,0200,0000,0200,0200,0000,
125	0200,0000,0000,0200,0000,0200,0200,0000,
126	0000,0200,0200,0000,0200,0000,0000,0201
127};
128
129#define	ERASE	tmode.c_cc[VERASE]
130#define	KILL	tmode.c_cc[VKILL]
131#define	EOT	tmode.c_cc[VEOF]
132
133#define	puts	Gputs
134
135static void	defttymode(void);
136static void	dingdong(int);
137static void	dogettytab(void);
138static int	getname(void);
139static void	interrupt(int);
140static void	oflush(void);
141static void	prompt(void);
142static void	putchr(int);
143static void	putf(const char *);
144static void	putpad(const char *);
145static void	puts(const char *);
146static void	timeoverrun(int);
147static char	*getline(int);
148static void	setttymode(int);
149static int	opentty(const char *, int);
150
151jmp_buf timeout;
152
153static void
154dingdong(int signo __unused)
155{
156	alarm(0);
157	longjmp(timeout, 1);
158}
159
160jmp_buf	intrupt;
161
162static void
163interrupt(int signo __unused)
164{
165	longjmp(intrupt, 1);
166}
167
168/*
169 * Action to take when getty is running too long.
170 */
171static void
172timeoverrun(int signo __unused)
173{
174
175	syslog(LOG_ERR, "getty exiting due to excessive running time");
176	exit(1);
177}
178
179int
180main(int argc, char *argv[])
181{
182	extern	char **environ;
183	int first_sleep = 1, first_time = 1;
184	struct rlimit limit;
185	int rval;
186
187	signal(SIGINT, SIG_IGN);
188	signal(SIGQUIT, SIG_IGN);
189
190	openlog("getty", LOG_CONS|LOG_PID, LOG_AUTH);
191	gethostname(hostname, sizeof(hostname) - 1);
192	hostname[sizeof(hostname) - 1] = '\0';
193	if (hostname[0] == '\0')
194		strcpy(hostname, "Amnesiac");
195
196	/*
197	 * Limit running time to deal with broken or dead lines.
198	 */
199	(void)signal(SIGXCPU, timeoverrun);
200	limit.rlim_max = RLIM_INFINITY;
201	limit.rlim_cur = GETTY_TIMEOUT;
202	(void)setrlimit(RLIMIT_CPU, &limit);
203
204	gettable("default", defent);
205	gendefaults();
206	tname = "default";
207	if (argc > 1)
208		tname = argv[1];
209
210	/*
211	 * The following is a work around for vhangup interactions
212	 * which cause great problems getting window systems started.
213	 * If the tty line is "-", we do the old style getty presuming
214	 * that the file descriptors are already set up for us.
215	 * J. Gettys - MIT Project Athena.
216	 */
217	if (argc <= 2 || strcmp(argv[2], "-") == 0)
218	    strcpy(ttyn, ttyname(STDIN_FILENO));
219	else {
220	    strcpy(ttyn, dev);
221	    strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
222	    if (strcmp(argv[0], "+") != 0) {
223		chown(ttyn, 0, 0);
224		chmod(ttyn, 0600);
225		revoke(ttyn);
226
227		/*
228		 * Do the first scan through gettytab.
229		 * Terminal mode parameters will be wrong until
230		 * defttymode() called, but they're irrelevant for
231		 * the initial setup of the terminal device.
232		 */
233		dogettytab();
234
235		/*
236		 * Init or answer modem sequence has been specified.
237		 */
238		if (IC || AC) {
239			if (!opentty(ttyn, O_RDWR|O_NONBLOCK))
240				exit(1);
241			defttymode();
242			setttymode(1);
243		}
244
245		if (IC) {
246			if (getty_chat(IC, CT, DC) > 0) {
247				syslog(LOG_ERR, "modem init problem on %s", ttyn);
248				(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
249				exit(1);
250			}
251		}
252
253		if (AC) {
254			int i, rfds;
255			struct timeval to;
256
257        		rfds = 1 << 0;	/* FD_SET */
258        		to.tv_sec = RT;
259        		to.tv_usec = 0;
260        		i = select(32, (fd_set*)&rfds, (fd_set*)NULL,
261        			       (fd_set*)NULL, RT ? &to : NULL);
262        		if (i < 0) {
263				syslog(LOG_ERR, "select %s: %m", ttyn);
264			} else if (i == 0) {
265				syslog(LOG_NOTICE, "recycle tty %s", ttyn);
266				(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
267				exit(0);  /* recycle for init */
268			}
269			i = getty_chat(AC, CT, DC);
270			if (i > 0) {
271				syslog(LOG_ERR, "modem answer problem on %s", ttyn);
272				(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
273				exit(1);
274			}
275		} else { /* maybe blocking open */
276			if (!opentty(ttyn, O_RDWR | (NC ? O_NONBLOCK : 0 )))
277				exit(1);
278		}
279	    }
280	}
281
282	defttymode();
283	for (;;) {
284
285		/*
286		 * if a delay was specified then sleep for that
287		 * number of seconds before writing the initial prompt
288		 */
289		if (first_sleep && DE) {
290		    sleep(DE);
291		    /* remove any noise */
292		    (void)tcflush(STDIN_FILENO, TCIOFLUSH);
293		}
294		first_sleep = 0;
295
296		setttymode(0);
297		if (AB) {
298			tname = autobaud();
299			dogettytab();
300			continue;
301		}
302		if (PS) {
303			tname = portselector();
304			dogettytab();
305			continue;
306		}
307		if (CL && *CL)
308			putpad(CL);
309		edithost(HE);
310
311		/* if this is the first time through this, and an
312		   issue file has been given, then send it */
313		if (first_time && IF) {
314			int fd;
315
316			if ((fd = open(IF, O_RDONLY)) != -1) {
317				char * cp;
318
319				while ((cp = getline(fd)) != NULL) {
320					  putf(cp);
321				}
322				close(fd);
323			}
324		}
325		first_time = 0;
326
327		if (IMP && *IMP && !(PL && PP))
328			system(IMP);
329		if (IM && *IM && !(PL && PP))
330			putf(IM);
331		if (setjmp(timeout)) {
332			cfsetispeed(&tmode, B0);
333			cfsetospeed(&tmode, B0);
334			(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
335			exit(1);
336		}
337		if (TO) {
338			signal(SIGALRM, dingdong);
339			alarm(TO);
340		}
341
342		rval = 0;
343		if (AL) {
344			const char *p = AL;
345			char *q = name;
346
347			while (*p && q < &name[sizeof name - 1]) {
348				if (isupper(*p))
349					upper = 1;
350				else if (islower(*p))
351					lower = 1;
352				else if (isdigit(*p))
353					digit = 1;
354				*q++ = *p++;
355			}
356		} else if (!(PL && PP))
357			rval = getname();
358		if (rval == 2 || (PL && PP)) {
359			oflush();
360			alarm(0);
361			limit.rlim_max = RLIM_INFINITY;
362			limit.rlim_cur = RLIM_INFINITY;
363			(void)setrlimit(RLIMIT_CPU, &limit);
364			execle(PP, "ppplogin", ttyn, (char *) 0, env);
365			syslog(LOG_ERR, "%s: %m", PP);
366			exit(1);
367		} else if (rval || AL) {
368			int i;
369
370			oflush();
371			alarm(0);
372			signal(SIGALRM, SIG_DFL);
373			if (name[0] == '\0')
374				continue;
375			if (name[0] == '-') {
376				puts("user names may not start with '-'.");
377				continue;
378			}
379			if (!(upper || lower || digit)) {
380				if (AL) {
381					syslog(LOG_ERR,
382					    "invalid auto-login name: %s", AL);
383					exit(1);
384				} else
385					continue;
386			}
387			set_flags(2);
388			if (crmod) {
389				tmode.c_iflag |= ICRNL;
390				tmode.c_oflag |= ONLCR;
391			}
392#if REALLY_OLD_TTYS
393			if (upper || UC)
394				tmode.sg_flags |= LCASE;
395			if (lower || LC)
396				tmode.sg_flags &= ~LCASE;
397#endif
398			if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
399				syslog(LOG_ERR, "tcsetattr %s: %m", ttyn);
400				exit(1);
401			}
402			signal(SIGINT, SIG_DFL);
403			for (i = 0; environ[i] != (char *)0; i++)
404				env[i] = environ[i];
405			makeenv(&env[i]);
406
407			limit.rlim_max = RLIM_INFINITY;
408			limit.rlim_cur = RLIM_INFINITY;
409			(void)setrlimit(RLIMIT_CPU, &limit);
410			execle(LO, "login", AL ? "-fp" : "-p", name,
411			    (char *) 0, env);
412			syslog(LOG_ERR, "%s: %m", LO);
413			exit(1);
414		}
415		alarm(0);
416		signal(SIGALRM, SIG_DFL);
417		signal(SIGINT, SIG_IGN);
418		if (NX && *NX) {
419			tname = NX;
420			dogettytab();
421		}
422	}
423}
424
425static int
426opentty(const char *tty, int flags)
427{
428	int i;
429	int failopenlogged = 0;
430
431	while ((i = open(tty, flags)) == -1)
432	{
433		if (!failopenlogged) {
434			syslog(LOG_ERR, "open %s: %m", tty);
435			failopenlogged = 1;
436		}
437		sleep(60);
438	}
439	if (login_tty(i) < 0) {
440		if (daemon(0,0) < 0) {
441			syslog(LOG_ERR,"daemon: %m");
442			close(i);
443			return 0;
444		}
445		if (login_tty(i) < 0) {
446			syslog(LOG_ERR, "login_tty %s: %m", tty);
447			close(i);
448			return 0;
449		}
450	}
451	return 1;
452}
453
454static void
455defttymode(void)
456{
457	struct termios def;
458
459	/* Start with default tty settings. */
460	if (tcgetattr(STDIN_FILENO, &tmode) < 0) {
461		syslog(LOG_ERR, "tcgetattr %s: %m", ttyn);
462		exit(1);
463	}
464	omode = tmode; /* fill c_cc for dogettytab() */
465	dogettytab();
466	/*
467	 * Don't rely on the driver too much, and initialize crucial
468	 * things according to <sys/ttydefaults.h>.  Avoid clobbering
469	 * the c_cc[] settings however, the console drivers might wish
470	 * to leave their idea of the preferred VERASE key value
471	 * there.
472	 */
473	cfmakesane(&def);
474	tmode.c_iflag = def.c_iflag;
475	tmode.c_oflag = def.c_oflag;
476	tmode.c_lflag = def.c_lflag;
477	tmode.c_cflag = def.c_cflag;
478	if (NC)
479		tmode.c_cflag |= CLOCAL;
480	omode = tmode;
481}
482
483static void
484setttymode(int raw)
485{
486	int off = 0;
487
488	(void)tcflush(STDIN_FILENO, TCIOFLUSH);	/* clear out the crap */
489	ioctl(STDIN_FILENO, FIONBIO, &off);	/* turn off non-blocking mode */
490	ioctl(STDIN_FILENO, FIOASYNC, &off);	/* ditto for async mode */
491
492	if (IS)
493		cfsetispeed(&tmode, speed(IS));
494	else if (SP)
495		cfsetispeed(&tmode, speed(SP));
496	if (OS)
497		cfsetospeed(&tmode, speed(OS));
498	else if (SP)
499		cfsetospeed(&tmode, speed(SP));
500	set_flags(0);
501	setchars();
502	if (raw)
503		cfmakeraw(&tmode);
504	if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
505		syslog(LOG_ERR, "tcsetattr %s: %m", ttyn);
506		exit(1);
507	}
508}
509
510
511static int
512getname(void)
513{
514	int c;
515	char *np;
516	unsigned char cs;
517	int ppp_state = 0;
518	int ppp_connection = 0;
519
520	/*
521	 * Interrupt may happen if we use CBREAK mode
522	 */
523	if (setjmp(intrupt)) {
524		signal(SIGINT, SIG_IGN);
525		return (0);
526	}
527	signal(SIGINT, interrupt);
528	set_flags(1);
529	prompt();
530	oflush();
531	if (PF > 0) {
532		sleep(PF);
533		PF = 0;
534	}
535	if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
536		syslog(LOG_ERR, "%s: %m", ttyn);
537		exit(1);
538	}
539	crmod = digit = lower = upper = 0;
540	np = name;
541	for (;;) {
542		oflush();
543		if (read(STDIN_FILENO, &cs, 1) <= 0)
544			exit(0);
545		if ((c = cs&0177) == 0)
546			return (0);
547
548		/* PPP detection state machine..
549		   Look for sequences:
550		   PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or
551		   PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC)
552		   See RFC1662.
553		   Derived from code from Michael Hancock, <michaelh@cet.co.jp>
554		   and Erik 'PPP' Olson, <eriko@wrq.com>
555		 */
556
557		if (PP && (cs == PPP_FRAME)) {
558			ppp_state = 1;
559		} else if (ppp_state == 1 && cs == PPP_STATION) {
560			ppp_state = 2;
561		} else if (ppp_state == 2 && cs == PPP_ESCAPE) {
562			ppp_state = 3;
563		} else if ((ppp_state == 2 && cs == PPP_CONTROL)
564			|| (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) {
565			ppp_state = 4;
566		} else if (ppp_state == 4 && cs == PPP_LCP_HI) {
567			ppp_state = 5;
568		} else if (ppp_state == 5 && cs == PPP_LCP_LOW) {
569			ppp_connection = 1;
570			break;
571		} else {
572			ppp_state = 0;
573		}
574
575		if (c == EOT || c == CTRL('d'))
576			exit(0);
577		if (c == '\r' || c == '\n' || np >= &name[sizeof name-1]) {
578			putf("\r\n");
579			break;
580		}
581		if (islower(c))
582			lower = 1;
583		else if (isupper(c))
584			upper = 1;
585		else if (c == ERASE || c == '\b' || c == 0177) {
586			if (np > name) {
587				np--;
588				if (cfgetospeed(&tmode) >= 1200)
589					puts("\b \b");
590				else
591					putchr(cs);
592			}
593			continue;
594		} else if (c == KILL || c == CTRL('u')) {
595			putchr('\r');
596			if (cfgetospeed(&tmode) < 1200)
597				putchr('\n');
598			/* this is the way they do it down under ... */
599			else if (np > name)
600				puts("                                     \r");
601			prompt();
602			digit = lower = upper = 0;
603			np = name;
604			continue;
605		} else if (isdigit(c))
606			digit = 1;
607		if (IG && (c <= ' ' || c > 0176))
608			continue;
609		*np++ = c;
610		putchr(cs);
611	}
612	signal(SIGINT, SIG_IGN);
613	*np = 0;
614	if (c == '\r')
615		crmod = 1;
616	if ((upper && !lower && !LC) || UC)
617		for (np = name; *np; np++)
618			if (isupper(*np))
619				*np = tolower(*np);
620	return (1 + ppp_connection);
621}
622
623static void
624putpad(const char *s)
625{
626	int pad = 0;
627	speed_t ospeed = cfgetospeed(&tmode);
628
629	if (isdigit(*s)) {
630		while (isdigit(*s)) {
631			pad *= 10;
632			pad += *s++ - '0';
633		}
634		pad *= 10;
635		if (*s == '.' && isdigit(s[1])) {
636			pad += s[1] - '0';
637			s += 2;
638		}
639	}
640
641	puts(s);
642	/*
643	 * If no delay needed, or output speed is
644	 * not comprehensible, then don't try to delay.
645	 */
646	if (pad == 0 || ospeed <= 0)
647		return;
648
649	/*
650	 * Round up by a half a character frame, and then do the delay.
651	 * Too bad there are no user program accessible programmed delays.
652	 * Transmitting pad characters slows many terminals down and also
653	 * loads the system.
654	 */
655	pad = (pad * ospeed + 50000) / 100000;
656	while (pad--)
657		putchr(*PC);
658}
659
660static void
661puts(const char *s)
662{
663	while (*s)
664		putchr(*s++);
665}
666
667char	outbuf[OBUFSIZ];
668int	obufcnt = 0;
669
670static void
671putchr(int cc)
672{
673	char c;
674
675	c = cc;
676	if (!NP) {
677		c |= partab[c&0177] & 0200;
678		if (OP)
679			c ^= 0200;
680	}
681	if (!UB) {
682		outbuf[obufcnt++] = c;
683		if (obufcnt >= OBUFSIZ)
684			oflush();
685	} else
686		write(STDOUT_FILENO, &c, 1);
687}
688
689static void
690oflush(void)
691{
692	if (obufcnt)
693		write(STDOUT_FILENO, outbuf, obufcnt);
694	obufcnt = 0;
695}
696
697static void
698prompt(void)
699{
700
701	putf(LM);
702	if (CO)
703		putchr('\n');
704}
705
706
707static char *
708getline(int fd)
709{
710	int i = 0;
711	static char linebuf[512];
712
713	/*
714	 * This is certainly slow, but it avoids having to include
715	 * stdio.h unnecessarily. Issue files should be small anyway.
716	 */
717	while (i < (sizeof linebuf - 3) && read(fd, linebuf+i, 1)==1) {
718		if (linebuf[i] == '\n') {
719			/* Don't rely on newline mode, assume raw */
720			linebuf[i++] = '\r';
721			linebuf[i++] = '\n';
722			linebuf[i] = '\0';
723			return linebuf;
724		}
725		++i;
726	}
727	linebuf[i] = '\0';
728	return i ? linebuf : 0;
729}
730
731static void
732putf(const char *cp)
733{
734	extern char editedhost[];
735	time_t t;
736	char *slash, db[100];
737
738	static struct utsname kerninfo;
739
740	if (!*kerninfo.sysname)
741		uname(&kerninfo);
742
743	while (*cp) {
744		if (*cp != '%') {
745			putchr(*cp++);
746			continue;
747		}
748		switch (*++cp) {
749
750		case 't':
751			slash = strrchr(ttyn, '/');
752			if (slash == (char *) 0)
753				puts(ttyn);
754			else
755				puts(&slash[1]);
756			break;
757
758		case 'h':
759			puts(editedhost);
760			break;
761
762		case 'd': {
763			t = (time_t)0;
764			(void)time(&t);
765			if (Lo)
766				(void)setlocale(LC_TIME, Lo);
767			(void)strftime(db, sizeof(db), DF, localtime(&t));
768			puts(db);
769			break;
770
771		case 's':
772			puts(kerninfo.sysname);
773			break;
774
775		case 'm':
776			puts(kerninfo.machine);
777			break;
778
779		case 'r':
780			puts(kerninfo.release);
781			break;
782
783		case 'v':
784			puts(kerninfo.version);
785			break;
786		}
787
788		case '%':
789			putchr('%');
790			break;
791		}
792		cp++;
793	}
794}
795
796/*
797 * Read a gettytab database entry and perform necessary quirks.
798 */
799static void
800dogettytab(void)
801{
802
803	/* Read the database entry. */
804	gettable(tname, tabent);
805
806	/*
807	 * Avoid inheriting the parity values from the default entry
808	 * if any of them is set in the current entry.
809	 * Mixing different parity settings is unreasonable.
810	 */
811	if (OPset || EPset || APset || NPset)
812		OPset = EPset = APset = NPset = 1;
813
814	/* Fill in default values for unset capabilities. */
815	setdefaults();
816}
817