main.c revision 262435
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/10/libexec/getty/main.c 262435 2014-02-24 08:21:49Z brueffer $");
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_ODELAY|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 (IM && *IM && !(PL && PP))
328			putf(IM);
329		if (setjmp(timeout)) {
330			cfsetispeed(&tmode, B0);
331			cfsetospeed(&tmode, B0);
332			(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
333			exit(1);
334		}
335		if (TO) {
336			signal(SIGALRM, dingdong);
337			alarm(TO);
338		}
339
340		rval = 0;
341		if (AL) {
342			const char *p = AL;
343			char *q = name;
344
345			while (*p && q < &name[sizeof name - 1]) {
346				if (isupper(*p))
347					upper = 1;
348				else if (islower(*p))
349					lower = 1;
350				else if (isdigit(*p))
351					digit = 1;
352				*q++ = *p++;
353			}
354		} else if (!(PL && PP))
355			rval = getname();
356		if (rval == 2 || (PL && PP)) {
357			oflush();
358			alarm(0);
359			limit.rlim_max = RLIM_INFINITY;
360			limit.rlim_cur = RLIM_INFINITY;
361			(void)setrlimit(RLIMIT_CPU, &limit);
362			execle(PP, "ppplogin", ttyn, (char *) 0, env);
363			syslog(LOG_ERR, "%s: %m", PP);
364			exit(1);
365		} else if (rval || AL) {
366			int i;
367
368			oflush();
369			alarm(0);
370			signal(SIGALRM, SIG_DFL);
371			if (name[0] == '\0')
372				continue;
373			if (name[0] == '-') {
374				puts("user names may not start with '-'.");
375				continue;
376			}
377			if (!(upper || lower || digit)) {
378				if (AL) {
379					syslog(LOG_ERR,
380					    "invalid auto-login name: %s", AL);
381					exit(1);
382				} else
383					continue;
384			}
385			set_flags(2);
386			if (crmod) {
387				tmode.c_iflag |= ICRNL;
388				tmode.c_oflag |= ONLCR;
389			}
390#if REALLY_OLD_TTYS
391			if (upper || UC)
392				tmode.sg_flags |= LCASE;
393			if (lower || LC)
394				tmode.sg_flags &= ~LCASE;
395#endif
396			if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
397				syslog(LOG_ERR, "tcsetattr %s: %m", ttyn);
398				exit(1);
399			}
400			signal(SIGINT, SIG_DFL);
401			for (i = 0; environ[i] != (char *)0; i++)
402				env[i] = environ[i];
403			makeenv(&env[i]);
404
405			limit.rlim_max = RLIM_INFINITY;
406			limit.rlim_cur = RLIM_INFINITY;
407			(void)setrlimit(RLIMIT_CPU, &limit);
408			execle(LO, "login", AL ? "-fp" : "-p", name,
409			    (char *) 0, env);
410			syslog(LOG_ERR, "%s: %m", LO);
411			exit(1);
412		}
413		alarm(0);
414		signal(SIGALRM, SIG_DFL);
415		signal(SIGINT, SIG_IGN);
416		if (NX && *NX) {
417			tname = NX;
418			dogettytab();
419		}
420	}
421}
422
423static int
424opentty(const char *tty, int flags)
425{
426	int i;
427	int failopenlogged = 0;
428
429	while ((i = open(tty, flags)) == -1)
430	{
431		if (!failopenlogged) {
432			syslog(LOG_ERR, "open %s: %m", tty);
433			failopenlogged = 1;
434		}
435		sleep(60);
436	}
437	if (login_tty(i) < 0) {
438		if (daemon(0,0) < 0) {
439			syslog(LOG_ERR,"daemon: %m");
440			close(i);
441			return 0;
442		}
443		if (login_tty(i) < 0) {
444			syslog(LOG_ERR, "login_tty %s: %m", tty);
445			close(i);
446			return 0;
447		}
448	}
449	return 1;
450}
451
452static void
453defttymode(void)
454{
455	struct termios def;
456
457	/* Start with default tty settings. */
458	if (tcgetattr(STDIN_FILENO, &tmode) < 0) {
459		syslog(LOG_ERR, "tcgetattr %s: %m", ttyn);
460		exit(1);
461	}
462	omode = tmode; /* fill c_cc for dogettytab() */
463	dogettytab();
464	/*
465	 * Don't rely on the driver too much, and initialize crucial
466	 * things according to <sys/ttydefaults.h>.  Avoid clobbering
467	 * the c_cc[] settings however, the console drivers might wish
468	 * to leave their idea of the preferred VERASE key value
469	 * there.
470	 */
471	cfmakesane(&def);
472	tmode.c_iflag = def.c_iflag;
473	tmode.c_oflag = def.c_oflag;
474	tmode.c_lflag = def.c_lflag;
475	tmode.c_cflag = def.c_cflag;
476	if (NC)
477		tmode.c_cflag |= CLOCAL;
478	omode = tmode;
479}
480
481static void
482setttymode(int raw)
483{
484	int off = 0;
485
486	(void)tcflush(STDIN_FILENO, TCIOFLUSH);	/* clear out the crap */
487	ioctl(STDIN_FILENO, FIONBIO, &off);	/* turn off non-blocking mode */
488	ioctl(STDIN_FILENO, FIOASYNC, &off);	/* ditto for async mode */
489
490	if (IS)
491		cfsetispeed(&tmode, speed(IS));
492	else if (SP)
493		cfsetispeed(&tmode, speed(SP));
494	if (OS)
495		cfsetospeed(&tmode, speed(OS));
496	else if (SP)
497		cfsetospeed(&tmode, speed(SP));
498	set_flags(0);
499	setchars();
500	if (raw)
501		cfmakeraw(&tmode);
502	if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
503		syslog(LOG_ERR, "tcsetattr %s: %m", ttyn);
504		exit(1);
505	}
506}
507
508
509static int
510getname(void)
511{
512	int c;
513	char *np;
514	unsigned char cs;
515	int ppp_state = 0;
516	int ppp_connection = 0;
517
518	/*
519	 * Interrupt may happen if we use CBREAK mode
520	 */
521	if (setjmp(intrupt)) {
522		signal(SIGINT, SIG_IGN);
523		return (0);
524	}
525	signal(SIGINT, interrupt);
526	set_flags(1);
527	prompt();
528	oflush();
529	if (PF > 0) {
530		sleep(PF);
531		PF = 0;
532	}
533	if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
534		syslog(LOG_ERR, "%s: %m", ttyn);
535		exit(1);
536	}
537	crmod = digit = lower = upper = 0;
538	np = name;
539	for (;;) {
540		oflush();
541		if (read(STDIN_FILENO, &cs, 1) <= 0)
542			exit(0);
543		if ((c = cs&0177) == 0)
544			return (0);
545
546		/* PPP detection state machine..
547		   Look for sequences:
548		   PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or
549		   PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC)
550		   See RFC1662.
551		   Derived from code from Michael Hancock, <michaelh@cet.co.jp>
552		   and Erik 'PPP' Olson, <eriko@wrq.com>
553		 */
554
555		if (PP && (cs == PPP_FRAME)) {
556			ppp_state = 1;
557		} else if (ppp_state == 1 && cs == PPP_STATION) {
558			ppp_state = 2;
559		} else if (ppp_state == 2 && cs == PPP_ESCAPE) {
560			ppp_state = 3;
561		} else if ((ppp_state == 2 && cs == PPP_CONTROL)
562			|| (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) {
563			ppp_state = 4;
564		} else if (ppp_state == 4 && cs == PPP_LCP_HI) {
565			ppp_state = 5;
566		} else if (ppp_state == 5 && cs == PPP_LCP_LOW) {
567			ppp_connection = 1;
568			break;
569		} else {
570			ppp_state = 0;
571		}
572
573		if (c == EOT || c == CTRL('d'))
574			exit(0);
575		if (c == '\r' || c == '\n' || np >= &name[sizeof name-1]) {
576			putf("\r\n");
577			break;
578		}
579		if (islower(c))
580			lower = 1;
581		else if (isupper(c))
582			upper = 1;
583		else if (c == ERASE || c == '\b' || c == 0177) {
584			if (np > name) {
585				np--;
586				if (cfgetospeed(&tmode) >= 1200)
587					puts("\b \b");
588				else
589					putchr(cs);
590			}
591			continue;
592		} else if (c == KILL || c == CTRL('u')) {
593			putchr('\r');
594			if (cfgetospeed(&tmode) < 1200)
595				putchr('\n');
596			/* this is the way they do it down under ... */
597			else if (np > name)
598				puts("                                     \r");
599			prompt();
600			digit = lower = upper = 0;
601			np = name;
602			continue;
603		} else if (isdigit(c))
604			digit = 1;
605		if (IG && (c <= ' ' || c > 0176))
606			continue;
607		*np++ = c;
608		putchr(cs);
609	}
610	signal(SIGINT, SIG_IGN);
611	*np = 0;
612	if (c == '\r')
613		crmod = 1;
614	if ((upper && !lower && !LC) || UC)
615		for (np = name; *np; np++)
616			if (isupper(*np))
617				*np = tolower(*np);
618	return (1 + ppp_connection);
619}
620
621static void
622putpad(const char *s)
623{
624	int pad = 0;
625	speed_t ospeed = cfgetospeed(&tmode);
626
627	if (isdigit(*s)) {
628		while (isdigit(*s)) {
629			pad *= 10;
630			pad += *s++ - '0';
631		}
632		pad *= 10;
633		if (*s == '.' && isdigit(s[1])) {
634			pad += s[1] - '0';
635			s += 2;
636		}
637	}
638
639	puts(s);
640	/*
641	 * If no delay needed, or output speed is
642	 * not comprehensible, then don't try to delay.
643	 */
644	if (pad == 0 || ospeed <= 0)
645		return;
646
647	/*
648	 * Round up by a half a character frame, and then do the delay.
649	 * Too bad there are no user program accessible programmed delays.
650	 * Transmitting pad characters slows many terminals down and also
651	 * loads the system.
652	 */
653	pad = (pad * ospeed + 50000) / 100000;
654	while (pad--)
655		putchr(*PC);
656}
657
658static void
659puts(const char *s)
660{
661	while (*s)
662		putchr(*s++);
663}
664
665char	outbuf[OBUFSIZ];
666int	obufcnt = 0;
667
668static void
669putchr(int cc)
670{
671	char c;
672
673	c = cc;
674	if (!NP) {
675		c |= partab[c&0177] & 0200;
676		if (OP)
677			c ^= 0200;
678	}
679	if (!UB) {
680		outbuf[obufcnt++] = c;
681		if (obufcnt >= OBUFSIZ)
682			oflush();
683	} else
684		write(STDOUT_FILENO, &c, 1);
685}
686
687static void
688oflush(void)
689{
690	if (obufcnt)
691		write(STDOUT_FILENO, outbuf, obufcnt);
692	obufcnt = 0;
693}
694
695static void
696prompt(void)
697{
698
699	putf(LM);
700	if (CO)
701		putchr('\n');
702}
703
704
705static char *
706getline(int fd)
707{
708	int i = 0;
709	static char linebuf[512];
710
711	/*
712	 * This is certainly slow, but it avoids having to include
713	 * stdio.h unnecessarily. Issue files should be small anyway.
714	 */
715	while (i < (sizeof linebuf - 3) && read(fd, linebuf+i, 1)==1) {
716		if (linebuf[i] == '\n') {
717			/* Don't rely on newline mode, assume raw */
718			linebuf[i++] = '\r';
719			linebuf[i++] = '\n';
720			linebuf[i] = '\0';
721			return linebuf;
722		}
723		++i;
724	}
725	linebuf[i] = '\0';
726	return i ? linebuf : 0;
727}
728
729static void
730putf(const char *cp)
731{
732	extern char editedhost[];
733	time_t t;
734	char *slash, db[100];
735
736	static struct utsname kerninfo;
737
738	if (!*kerninfo.sysname)
739		uname(&kerninfo);
740
741	while (*cp) {
742		if (*cp != '%') {
743			putchr(*cp++);
744			continue;
745		}
746		switch (*++cp) {
747
748		case 't':
749			slash = strrchr(ttyn, '/');
750			if (slash == (char *) 0)
751				puts(ttyn);
752			else
753				puts(&slash[1]);
754			break;
755
756		case 'h':
757			puts(editedhost);
758			break;
759
760		case 'd': {
761			t = (time_t)0;
762			(void)time(&t);
763			if (Lo)
764				(void)setlocale(LC_TIME, Lo);
765			(void)strftime(db, sizeof(db), DF, localtime(&t));
766			puts(db);
767			break;
768
769		case 's':
770			puts(kerninfo.sysname);
771			break;
772
773		case 'm':
774			puts(kerninfo.machine);
775			break;
776
777		case 'r':
778			puts(kerninfo.release);
779			break;
780
781		case 'v':
782			puts(kerninfo.version);
783			break;
784		}
785
786		case '%':
787			putchr('%');
788			break;
789		}
790		cp++;
791	}
792}
793
794/*
795 * Read a gettytab database entry and perform necessary quirks.
796 */
797static void
798dogettytab(void)
799{
800
801	/* Read the database entry. */
802	gettable(tname, tabent);
803
804	/*
805	 * Avoid inheriting the parity values from the default entry
806	 * if any of them is set in the current entry.
807	 * Mixing different parity settings is unreasonable.
808	 */
809	if (OPset || EPset || APset || NPset)
810		OPset = EPset = APset = NPset = 1;
811
812	/* Fill in default values for unset capabilities. */
813	setdefaults();
814}
815