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