main.c revision 117738
11592Srgrimes/*-
215645Sjoerg * Copyright (c) 1980, 1993
315645Sjoerg *	The Regents of the University of California.  All rights reserved.
41592Srgrimes *
51592Srgrimes * Redistribution and use in source and binary forms, with or without
61592Srgrimes * modification, are permitted provided that the following conditions
71592Srgrimes * are met:
81592Srgrimes * 1. Redistributions of source code must retain the above copyright
91592Srgrimes *    notice, this list of conditions and the following disclaimer.
101592Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111592Srgrimes *    notice, this list of conditions and the following disclaimer in the
121592Srgrimes *    documentation and/or other materials provided with the distribution.
131592Srgrimes * 3. All advertising materials mentioning features or use of this software
141592Srgrimes *    must display the following acknowledgement:
151592Srgrimes *	This product includes software developed by the University of
161592Srgrimes *	California, Berkeley and its contributors.
171592Srgrimes * 4. Neither the name of the University nor the names of its contributors
181592Srgrimes *    may be used to endorse or promote products derived from this software
191592Srgrimes *    without specific prior written permission.
201592Srgrimes *
211592Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221592Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231592Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241592Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251592Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261592Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271592Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281592Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291592Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301592Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311592Srgrimes * SUCH DAMAGE.
321592Srgrimes */
331592Srgrimes
341592Srgrimes#ifndef lint
3531331Scharnierstatic const char copyright[] =
3615645Sjoerg"@(#) Copyright (c) 1980, 1993\n\
3715645Sjoerg	The Regents of the University of California.  All rights reserved.\n";
381592Srgrimes#endif /* not lint */
391592Srgrimes
401592Srgrimes#ifndef lint
4131331Scharnier#if 0
4231331Scharnierstatic char sccsid[] = "@(#)from: main.c	8.1 (Berkeley) 6/20/93";
4331331Scharnier#endif
4431331Scharnierstatic const char rcsid[] =
4550476Speter  "$FreeBSD: head/libexec/getty/main.c 117738 2003-07-18 16:25:55Z yar $";
461592Srgrimes#endif /* not lint */
471592Srgrimes
481592Srgrimes#include <sys/param.h>
4915645Sjoerg#include <sys/ioctl.h>
5091216Sbde#include <sys/time.h>
5115645Sjoerg#include <sys/resource.h>
5291216Sbde#include <sys/stat.h>
5315645Sjoerg#include <sys/ttydefaults.h>
5415645Sjoerg#include <sys/utsname.h>
5566907Swollman
5631331Scharnier#include <ctype.h>
5715645Sjoerg#include <errno.h>
582286Sjkh#include <fcntl.h>
5931331Scharnier#include <locale.h>
6015645Sjoerg#include <libutil.h>
612286Sjkh#include <setjmp.h>
6215645Sjoerg#include <signal.h>
6315645Sjoerg#include <stdlib.h>
6415645Sjoerg#include <string.h>
652286Sjkh#include <syslog.h>
6615645Sjoerg#include <termios.h>
6715645Sjoerg#include <time.h>
682286Sjkh#include <unistd.h>
6915645Sjoerg
7091216Sbde#include "extern.h"
711592Srgrimes#include "gettytab.h"
721592Srgrimes#include "pathnames.h"
731592Srgrimes
7415645Sjoerg/*
7515645Sjoerg * Set the amount of running time that getty should accumulate
7615645Sjoerg * before deciding that something is wrong and exit.
7715645Sjoerg */
7815645Sjoerg#define GETTY_TIMEOUT	60 /* seconds */
791592Srgrimes
8015645Sjoerg#undef CTRL
8115645Sjoerg#define CTRL(x)  (x&037)
8215645Sjoerg
8319697Spst/* defines for auto detection of incoming PPP calls (->PAP/CHAP) */
8419697Spst
8519697Spst#define PPP_FRAME           0x7e  /* PPP Framing character */
8619697Spst#define PPP_STATION         0xff  /* "All Station" character */
8719697Spst#define PPP_ESCAPE          0x7d  /* Escape Character */
8819697Spst#define PPP_CONTROL         0x03  /* PPP Control Field */
8919697Spst#define PPP_CONTROL_ESCAPED 0x23  /* PPP Control Field, escaped */
9019697Spst#define PPP_LCP_HI          0xc0  /* LCP protocol - high byte */
9119697Spst#define PPP_LCP_LOW         0x21  /* LCP protocol - low byte */
9219697Spst
93116533Syar/* original mode; flags've been reset using values from <sys/ttydefaults.h> */
94116533Syarstruct termios omode;
95116533Syar/* current mode */
96116533Syarstruct termios tmode;
9715645Sjoerg
981592Srgrimesint crmod, digit, lower, upper;
991592Srgrimes
1001592Srgrimeschar	hostname[MAXHOSTNAMELEN];
10122400Sdavidnchar	name[MAXLOGNAME*3];
1021592Srgrimeschar	dev[] = _PATH_DEV;
1031592Srgrimeschar	ttyn[32];
1041592Srgrimes
1051592Srgrimes#define	OBUFSIZ		128
1061592Srgrimes#define	TABBUFSIZ	512
1071592Srgrimes
1081592Srgrimeschar	defent[TABBUFSIZ];
1091592Srgrimeschar	tabent[TABBUFSIZ];
110116533Syarconst	char *tname;
1111592Srgrimes
1121592Srgrimeschar	*env[128];
1131592Srgrimes
1141592Srgrimeschar partab[] = {
1151592Srgrimes	0001,0201,0201,0001,0201,0001,0001,0201,
1161592Srgrimes	0202,0004,0003,0205,0005,0206,0201,0001,
1171592Srgrimes	0201,0001,0001,0201,0001,0201,0201,0001,
1181592Srgrimes	0001,0201,0201,0001,0201,0001,0001,0201,
1191592Srgrimes	0200,0000,0000,0200,0000,0200,0200,0000,
1201592Srgrimes	0000,0200,0200,0000,0200,0000,0000,0200,
1211592Srgrimes	0000,0200,0200,0000,0200,0000,0000,0200,
1221592Srgrimes	0200,0000,0000,0200,0000,0200,0200,0000,
1231592Srgrimes	0200,0000,0000,0200,0000,0200,0200,0000,
1241592Srgrimes	0000,0200,0200,0000,0200,0000,0000,0200,
1251592Srgrimes	0000,0200,0200,0000,0200,0000,0000,0200,
1261592Srgrimes	0200,0000,0000,0200,0000,0200,0200,0000,
1271592Srgrimes	0000,0200,0200,0000,0200,0000,0000,0200,
1281592Srgrimes	0200,0000,0000,0200,0000,0200,0200,0000,
1291592Srgrimes	0200,0000,0000,0200,0000,0200,0200,0000,
1301592Srgrimes	0000,0200,0200,0000,0200,0000,0000,0201
1311592Srgrimes};
1321592Srgrimes
13315645Sjoerg#define	ERASE	tmode.c_cc[VERASE]
13415645Sjoerg#define	KILL	tmode.c_cc[VKILL]
13515645Sjoerg#define	EOT	tmode.c_cc[VEOF]
1361592Srgrimes
13740083Sjkh#define	puts	Gputs
13840083Sjkh
139117738Syarstatic void	defttymode(void);
14090301Simpstatic void	dingdong(int);
141116533Syarstatic void	dogettytab(void);
14290301Simpstatic int	getname(void);
14390301Simpstatic void	interrupt(int);
14490301Simpstatic void	oflush(void);
14590301Simpstatic void	prompt(void);
14690301Simpstatic void	putchr(int);
14790301Simpstatic void	putf(const char *);
14890301Simpstatic void	putpad(const char *);
14990301Simpstatic void	puts(const char *);
15090301Simpstatic void	timeoverrun(int);
15190301Simpstatic char	*getline(int);
152116164Syarstatic void	setttymode(int);
15390301Simpstatic int	opentty(const char *, int);
15415645Sjoerg
15522208Sdavidnjmp_buf timeout;
15622208Sdavidn
1571592Srgrimesstatic void
15890302Simpdingdong(int signo __unused)
1591592Srgrimes{
1601592Srgrimes	alarm(0);
1611592Srgrimes	longjmp(timeout, 1);
1621592Srgrimes}
1631592Srgrimes
1641592Srgrimesjmp_buf	intrupt;
1651592Srgrimes
1661592Srgrimesstatic void
16790302Simpinterrupt(int signo __unused)
1681592Srgrimes{
1691592Srgrimes	longjmp(intrupt, 1);
1701592Srgrimes}
1711592Srgrimes
17215645Sjoerg/*
17315645Sjoerg * Action to take when getty is running too long.
17415645Sjoerg */
17515645Sjoergstatic void
17690302Simptimeoverrun(int signo __unused)
17715645Sjoerg{
17815645Sjoerg
17931331Scharnier	syslog(LOG_ERR, "getty exiting due to excessive running time");
18015645Sjoerg	exit(1);
18115645Sjoerg}
18215645Sjoerg
18315645Sjoergint
18490301Simpmain(int argc, char *argv[])
1851592Srgrimes{
1862286Sjkh	extern	char **environ;
18722491Sdavidn	int first_sleep = 1, first_time = 1;
18815645Sjoerg	struct rlimit limit;
18919697Spst	int rval;
1901592Srgrimes
1911592Srgrimes	signal(SIGINT, SIG_IGN);
1922391Sache	signal(SIGQUIT, SIG_IGN);
1932286Sjkh
19415645Sjoerg	openlog("getty", LOG_ODELAY|LOG_CONS|LOG_PID, LOG_AUTH);
19545422Sbrian	gethostname(hostname, sizeof(hostname) - 1);
19645422Sbrian	hostname[sizeof(hostname) - 1] = '\0';
1971592Srgrimes	if (hostname[0] == '\0')
1981592Srgrimes		strcpy(hostname, "Amnesiac");
19915645Sjoerg
2001592Srgrimes	/*
20115645Sjoerg	 * Limit running time to deal with broken or dead lines.
20215645Sjoerg	 */
20315645Sjoerg	(void)signal(SIGXCPU, timeoverrun);
20415645Sjoerg	limit.rlim_max = RLIM_INFINITY;
20515645Sjoerg	limit.rlim_cur = GETTY_TIMEOUT;
20615645Sjoerg	(void)setrlimit(RLIMIT_CPU, &limit);
20715645Sjoerg
20822208Sdavidn	gettable("default", defent);
20922208Sdavidn	gendefaults();
21022208Sdavidn	tname = "default";
211116329Sgreen	if (argc > 1)
21222208Sdavidn		tname = argv[1];
21322208Sdavidn
21415645Sjoerg	/*
2151592Srgrimes	 * The following is a work around for vhangup interactions
2161592Srgrimes	 * which cause great problems getting window systems started.
2171592Srgrimes	 * If the tty line is "-", we do the old style getty presuming
2188870Srgrimes	 * that the file descriptors are already set up for us.
2191592Srgrimes	 * J. Gettys - MIT Project Athena.
2201592Srgrimes	 */
221116533Syar	if (argc <= 2 || strcmp(argv[2], "-") == 0)
22222208Sdavidn	    strcpy(ttyn, ttyname(STDIN_FILENO));
223116533Syar	else {
2241592Srgrimes	    strcpy(ttyn, dev);
2251592Srgrimes	    strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
2261592Srgrimes	    if (strcmp(argv[0], "+") != 0) {
2271592Srgrimes		chown(ttyn, 0, 0);
2281592Srgrimes		chmod(ttyn, 0600);
2291592Srgrimes		revoke(ttyn);
23022208Sdavidn
231116533Syar		/*
232116533Syar		 * Do the first scan through gettytab.
233116533Syar		 * Terminal mode parameters will be wrong until
234116533Syar		 * defttymode() called, but they're irrelevant for
235116533Syar		 * the initial setup of the terminal device.
23622208Sdavidn		 */
237116533Syar		dogettytab();
238116533Syar
239116533Syar		/*
240116533Syar		 * Init or answer modem sequence has been specified.
241116533Syar		 */
242116533Syar		if (IC || AC) {
24322208Sdavidn			if (!opentty(ttyn, O_RDWR|O_NONBLOCK))
24422208Sdavidn				exit(1);
245116533Syar			defttymode();
246116533Syar			setttymode(1);
247116533Syar		}
248116533Syar
249116533Syar		if (IC) {
25022208Sdavidn			if (getty_chat(IC, CT, DC) > 0) {
25122208Sdavidn				syslog(LOG_ERR, "modem init problem on %s", ttyn);
25222491Sdavidn				(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
25322208Sdavidn				exit(1);
2541592Srgrimes			}
2551592Srgrimes		}
25622208Sdavidn
25722208Sdavidn		if (AC) {
25822208Sdavidn			int i, rfds;
25990302Simp			struct timeval to;
26022208Sdavidn
26122208Sdavidn        		rfds = 1 << 0;	/* FD_SET */
26290302Simp        		to.tv_sec = RT;
26390302Simp        		to.tv_usec = 0;
26422208Sdavidn        		i = select(32, (fd_set*)&rfds, (fd_set*)NULL,
26590302Simp        			       (fd_set*)NULL, RT ? &to : NULL);
26622208Sdavidn        		if (i < 0) {
26722208Sdavidn				syslog(LOG_ERR, "select %s: %m", ttyn);
26822208Sdavidn			} else if (i == 0) {
26922208Sdavidn				syslog(LOG_NOTICE, "recycle tty %s", ttyn);
27022491Sdavidn				(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
27122208Sdavidn				exit(0);  /* recycle for init */
27222208Sdavidn			}
27322208Sdavidn			i = getty_chat(AC, CT, DC);
27422208Sdavidn			if (i > 0) {
27522208Sdavidn				syslog(LOG_ERR, "modem answer problem on %s", ttyn);
27622491Sdavidn				(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
27722208Sdavidn				exit(1);
27822208Sdavidn			}
27964076Snsayer		} else { /* maybe blocking open */
28064076Snsayer			if (!opentty(ttyn, O_RDWR | (NC ? O_NONBLOCK : 0 )))
28122208Sdavidn				exit(1);
28222208Sdavidn		}
2831592Srgrimes	    }
2841592Srgrimes	}
2851592Srgrimes
286116533Syar	defttymode();
2871592Srgrimes	for (;;) {
2881592Srgrimes
28922491Sdavidn		/*
29022491Sdavidn		 * if a delay was specified then sleep for that
29122491Sdavidn		 * number of seconds before writing the initial prompt
29222491Sdavidn		 */
29322491Sdavidn		if (first_sleep && DE) {
29422491Sdavidn		    sleep(DE);
29522491Sdavidn		    /* remove any noise */
29622491Sdavidn		    (void)tcflush(STDIN_FILENO, TCIOFLUSH);
29722491Sdavidn		}
29822491Sdavidn		first_sleep = 0;
29922491Sdavidn
300116164Syar		setttymode(0);
3011592Srgrimes		if (AB) {
3021592Srgrimes			tname = autobaud();
303116533Syar			dogettytab();
3041592Srgrimes			continue;
3051592Srgrimes		}
3061592Srgrimes		if (PS) {
3071592Srgrimes			tname = portselector();
308116533Syar			dogettytab();
3091592Srgrimes			continue;
3101592Srgrimes		}
3111592Srgrimes		if (CL && *CL)
3121592Srgrimes			putpad(CL);
3131592Srgrimes		edithost(HE);
31421120Smsmith
31522208Sdavidn		/* if this is the first time through this, and an
31622208Sdavidn		   issue file has been given, then send it */
31722208Sdavidn		if (first_time && IF) {
31822208Sdavidn			int fd;
31922208Sdavidn
32022208Sdavidn			if ((fd = open(IF, O_RDONLY)) != -1) {
32122208Sdavidn				char * cp;
32222208Sdavidn
32322208Sdavidn				while ((cp = getline(fd)) != NULL) {
32422208Sdavidn					  putf(cp);
32522208Sdavidn				}
32622208Sdavidn				close(fd);
32722208Sdavidn			}
32822208Sdavidn		}
32922491Sdavidn		first_time = 0;
33022208Sdavidn
331109555Ssobomax		if (IM && *IM && !(PL && PP))
3321592Srgrimes			putf(IM);
3331592Srgrimes		if (setjmp(timeout)) {
33415659Sache			cfsetispeed(&tmode, B0);
33515659Sache			cfsetospeed(&tmode, B0);
33622208Sdavidn			(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
3371592Srgrimes			exit(1);
3381592Srgrimes		}
3391592Srgrimes		if (TO) {
3401592Srgrimes			signal(SIGALRM, dingdong);
3411592Srgrimes			alarm(TO);
3421592Srgrimes		}
343115900Syar
344115900Syar		rval = 0;
34545291Speter		if (AL) {
34645291Speter			const char *p = AL;
34745291Speter			char *q = name;
34845291Speter
34945291Speter			while (*p && q < &name[sizeof name - 1]) {
35045291Speter				if (isupper(*p))
35145291Speter					upper = 1;
35245291Speter				else if (islower(*p))
35345291Speter					lower = 1;
35445291Speter				else if (isdigit(*p))
355116154Syar					digit = 1;
35645291Speter				*q++ = *p++;
35745291Speter			}
358109540Ssobomax		} else if (!(PL && PP))
35945291Speter			rval = getname();
360109540Ssobomax		if (rval == 2 || (PL && PP)) {
36126415Sdavidn			oflush();
36226415Sdavidn			alarm(0);
36344615Sbrian			limit.rlim_max = RLIM_INFINITY;
36444615Sbrian			limit.rlim_cur = RLIM_INFINITY;
36544615Sbrian			(void)setrlimit(RLIMIT_CPU, &limit);
36619697Spst			execle(PP, "ppplogin", ttyn, (char *) 0, env);
36719697Spst			syslog(LOG_ERR, "%s: %m", PP);
36819697Spst			exit(1);
36945291Speter		} else if (rval || AL) {
37090301Simp			int i;
3711592Srgrimes
37215645Sjoerg			oflush();
3731592Srgrimes			alarm(0);
3741592Srgrimes			signal(SIGALRM, SIG_DFL);
375115900Syar			if (name[0] == '\0')
376115900Syar				continue;
3771592Srgrimes			if (name[0] == '-') {
3781592Srgrimes				puts("user names may not start with '-'.");
3791592Srgrimes				continue;
3801592Srgrimes			}
381115900Syar			if (!(upper || lower || digit)) {
382115900Syar				if (AL) {
383115900Syar					syslog(LOG_ERR,
384115900Syar					    "invalid auto-login name: %s", AL);
385115900Syar					exit(1);
386115900Syar				} else
387115900Syar					continue;
388115900Syar			}
38956725Sbde			set_flags(2);
39015645Sjoerg			if (crmod) {
39115645Sjoerg				tmode.c_iflag |= ICRNL;
39215645Sjoerg				tmode.c_oflag |= ONLCR;
39315645Sjoerg			}
39415645Sjoerg#if REALLY_OLD_TTYS
39515645Sjoerg			if (upper || UC)
39615645Sjoerg				tmode.sg_flags |= LCASE;
39715645Sjoerg			if (lower || LC)
39815645Sjoerg				tmode.sg_flags &= ~LCASE;
39915645Sjoerg#endif
40022208Sdavidn			if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
40122208Sdavidn				syslog(LOG_ERR, "tcsetattr %s: %m", ttyn);
40215645Sjoerg				exit(1);
40315645Sjoerg			}
40415645Sjoerg			signal(SIGINT, SIG_DFL);
4051592Srgrimes			for (i = 0; environ[i] != (char *)0; i++)
4061592Srgrimes				env[i] = environ[i];
4071592Srgrimes			makeenv(&env[i]);
4081592Srgrimes
40915645Sjoerg			limit.rlim_max = RLIM_INFINITY;
41015645Sjoerg			limit.rlim_cur = RLIM_INFINITY;
41115645Sjoerg			(void)setrlimit(RLIMIT_CPU, &limit);
41245291Speter			execle(LO, "login", AL ? "-fp" : "-p", name,
41345291Speter			    (char *) 0, env);
4141592Srgrimes			syslog(LOG_ERR, "%s: %m", LO);
4151592Srgrimes			exit(1);
4161592Srgrimes		}
4171592Srgrimes		alarm(0);
4181592Srgrimes		signal(SIGALRM, SIG_DFL);
41915645Sjoerg		signal(SIGINT, SIG_IGN);
420116164Syar		if (NX && *NX) {
4211592Srgrimes			tname = NX;
422116533Syar			dogettytab();
423116164Syar		}
4241592Srgrimes	}
4251592Srgrimes}
4261592Srgrimes
42715645Sjoergstatic int
42890302Simpopentty(const char *tty, int flags)
42922208Sdavidn{
43022208Sdavidn	int i, j = 0;
43122208Sdavidn	int failopenlogged = 0;
43222208Sdavidn
43390302Simp	while (j < 10 && (i = open(tty, flags)) == -1)
43422208Sdavidn	{
43522208Sdavidn		if (((j % 10) == 0) && (errno != ENXIO || !failopenlogged)) {
43690302Simp			syslog(LOG_ERR, "open %s: %m", tty);
43722208Sdavidn			failopenlogged = 1;
43822208Sdavidn		}
43922208Sdavidn		j++;
44022208Sdavidn		sleep(60);
44122208Sdavidn	}
44222208Sdavidn	if (i == -1) {
44390302Simp		syslog(LOG_ERR, "open %s: %m", tty);
44422208Sdavidn		return 0;
44522208Sdavidn	}
44622208Sdavidn	else {
44768888Sjwd		if (login_tty(i) < 0) {
44868888Sjwd			if (daemon(0,0) < 0) {
44968888Sjwd				syslog(LOG_ERR,"daemon: %m");
45068888Sjwd				close(i);
45168888Sjwd				return 0;
45268888Sjwd			}
45368888Sjwd			if (login_tty(i) < 0) {
45490302Simp				syslog(LOG_ERR, "login_tty %s: %m", tty);
45568888Sjwd				close(i);
45668888Sjwd				return 0;
45768888Sjwd			}
45868888Sjwd		}
45922208Sdavidn		return 1;
46022208Sdavidn	}
46122208Sdavidn}
46222208Sdavidn
46322208Sdavidnstatic void
464116533Syardefttymode()
46522208Sdavidn{
466116533Syar
467116533Syar	/* Start with default tty settings. */
46822208Sdavidn	if (tcgetattr(STDIN_FILENO, &tmode) < 0) {
46922208Sdavidn		syslog(LOG_ERR, "tcgetattr %s: %m", ttyn);
47022208Sdavidn		exit(1);
47122208Sdavidn	}
472116533Syar	omode = tmode; /* fill c_cc for dogettytab() */
473116533Syar	dogettytab();
474116533Syar	/*
475116533Syar	 * Don't rely on the driver too much, and initialize crucial
476116533Syar	 * things according to <sys/ttydefaults.h>.  Avoid clobbering
477116533Syar	 * the c_cc[] settings however, the console drivers might wish
478116533Syar	 * to leave their idea of the preferred VERASE key value
479116533Syar	 * there.
480116533Syar	 */
48122208Sdavidn	tmode.c_iflag = TTYDEF_IFLAG;
482116533Syar	tmode.c_oflag = TTYDEF_OFLAG;
483116533Syar	tmode.c_lflag = TTYDEF_LFLAG;
484116533Syar	tmode.c_cflag = TTYDEF_CFLAG;
485116533Syar	if (NC)
486116533Syar		tmode.c_cflag |= CLOCAL;
487116533Syar	omode = tmode;
48822208Sdavidn}
48922208Sdavidn
49022208Sdavidnstatic void
491116164Syarsetttymode(int raw)
49222208Sdavidn{
49322208Sdavidn	int off = 0;
49422208Sdavidn
49522208Sdavidn	(void)tcflush(STDIN_FILENO, TCIOFLUSH);	/* clear out the crap */
49622208Sdavidn	ioctl(STDIN_FILENO, FIONBIO, &off);	/* turn off non-blocking mode */
49722208Sdavidn	ioctl(STDIN_FILENO, FIOASYNC, &off);	/* ditto for async mode */
49822208Sdavidn
49922208Sdavidn	if (IS)
50022208Sdavidn		cfsetispeed(&tmode, speed(IS));
50122208Sdavidn	else if (SP)
50222208Sdavidn		cfsetispeed(&tmode, speed(SP));
50322208Sdavidn	if (OS)
50422208Sdavidn		cfsetospeed(&tmode, speed(OS));
50522208Sdavidn	else if (SP)
50622208Sdavidn		cfsetospeed(&tmode, speed(SP));
50756725Sbde	set_flags(0);
50822208Sdavidn	setchars();
50922208Sdavidn	if (raw)
51022208Sdavidn		cfmakeraw(&tmode);
51122208Sdavidn	if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
51222208Sdavidn		syslog(LOG_ERR, "tcsetattr %s: %m", ttyn);
51322208Sdavidn		exit(1);
51422208Sdavidn	}
51522208Sdavidn}
51622208Sdavidn
51722208Sdavidn
51822208Sdavidnstatic int
51990301Simpgetname(void)
5201592Srgrimes{
52190301Simp	int c;
52290301Simp	char *np;
52319697Spst	unsigned char cs;
52422208Sdavidn	int ppp_state = 0;
52519697Spst	int ppp_connection = 0;
5261592Srgrimes
5271592Srgrimes	/*
5281592Srgrimes	 * Interrupt may happen if we use CBREAK mode
5291592Srgrimes	 */
5301592Srgrimes	if (setjmp(intrupt)) {
5311592Srgrimes		signal(SIGINT, SIG_IGN);
5321592Srgrimes		return (0);
5331592Srgrimes	}
5341592Srgrimes	signal(SIGINT, interrupt);
53556725Sbde	set_flags(1);
5361592Srgrimes	prompt();
5372286Sjkh	oflush();
5381592Srgrimes	if (PF > 0) {
5391592Srgrimes		sleep(PF);
5401592Srgrimes		PF = 0;
5411592Srgrimes	}
54222208Sdavidn	if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
54315645Sjoerg		syslog(LOG_ERR, "%s: %m", ttyn);
54415645Sjoerg		exit(1);
54515645Sjoerg	}
5461592Srgrimes	crmod = digit = lower = upper = 0;
5471592Srgrimes	np = name;
5481592Srgrimes	for (;;) {
5491592Srgrimes		oflush();
5501592Srgrimes		if (read(STDIN_FILENO, &cs, 1) <= 0)
5511592Srgrimes			exit(0);
5521592Srgrimes		if ((c = cs&0177) == 0)
5531592Srgrimes			return (0);
55419697Spst
55519697Spst		/* PPP detection state machine..
55619697Spst		   Look for sequences:
55719697Spst		   PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or
55819697Spst		   PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC)
55919697Spst		   See RFC1662.
56019697Spst		   Derived from code from Michael Hancock, <michaelh@cet.co.jp>
56119697Spst		   and Erik 'PPP' Olson, <eriko@wrq.com>
56219697Spst		 */
56319697Spst
56419697Spst		if (PP && (cs == PPP_FRAME)) {
56519697Spst			ppp_state = 1;
56619697Spst		} else if (ppp_state == 1 && cs == PPP_STATION) {
56719697Spst			ppp_state = 2;
56819697Spst		} else if (ppp_state == 2 && cs == PPP_ESCAPE) {
56919697Spst			ppp_state = 3;
57019697Spst		} else if ((ppp_state == 2 && cs == PPP_CONTROL)
57119697Spst			|| (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) {
57219697Spst			ppp_state = 4;
57319697Spst		} else if (ppp_state == 4 && cs == PPP_LCP_HI) {
57419697Spst			ppp_state = 5;
57519697Spst		} else if (ppp_state == 5 && cs == PPP_LCP_LOW) {
57619697Spst			ppp_connection = 1;
57719697Spst			break;
57819697Spst		} else {
57919697Spst			ppp_state = 0;
58019697Spst		}
58119697Spst
58215645Sjoerg		if (c == EOT || c == CTRL('d'))
583115900Syar			exit(0);
58422211Sdavidn		if (c == '\r' || c == '\n' || np >= &name[sizeof name-1]) {
5851592Srgrimes			putf("\r\n");
5861592Srgrimes			break;
5871592Srgrimes		}
5881592Srgrimes		if (islower(c))
5891592Srgrimes			lower = 1;
5901592Srgrimes		else if (isupper(c))
5911592Srgrimes			upper = 1;
5922286Sjkh		else if (c == ERASE || c == '\b' || c == 0177) {
5931592Srgrimes			if (np > name) {
5941592Srgrimes				np--;
59515645Sjoerg				if (cfgetospeed(&tmode) >= 1200)
5961592Srgrimes					puts("\b \b");
5971592Srgrimes				else
5981592Srgrimes					putchr(cs);
5991592Srgrimes			}
6001592Srgrimes			continue;
60115645Sjoerg		} else if (c == KILL || c == CTRL('u')) {
6021592Srgrimes			putchr('\r');
60315645Sjoerg			if (cfgetospeed(&tmode) < 1200)
6041592Srgrimes				putchr('\n');
6051592Srgrimes			/* this is the way they do it down under ... */
6061592Srgrimes			else if (np > name)
6071592Srgrimes				puts("                                     \r");
6081592Srgrimes			prompt();
609115900Syar			digit = lower = upper = 0;
6101592Srgrimes			np = name;
6111592Srgrimes			continue;
6121592Srgrimes		} else if (isdigit(c))
613116154Syar			digit = 1;
6141592Srgrimes		if (IG && (c <= ' ' || c > 0176))
6151592Srgrimes			continue;
6161592Srgrimes		*np++ = c;
6171592Srgrimes		putchr(cs);
6181592Srgrimes	}
6191592Srgrimes	signal(SIGINT, SIG_IGN);
6201592Srgrimes	*np = 0;
6211592Srgrimes	if (c == '\r')
6221592Srgrimes		crmod = 1;
62315645Sjoerg	if ((upper && !lower && !LC) || UC)
6241592Srgrimes		for (np = name; *np; np++)
6251592Srgrimes			if (isupper(*np))
6261592Srgrimes				*np = tolower(*np);
62719697Spst	return (1 + ppp_connection);
6281592Srgrimes}
6291592Srgrimes
63015645Sjoergstatic void
63190301Simpputpad(const char *s)
6321592Srgrimes{
63390301Simp	int pad = 0;
63415645Sjoerg	speed_t ospeed = cfgetospeed(&tmode);
6351592Srgrimes
6361592Srgrimes	if (isdigit(*s)) {
6371592Srgrimes		while (isdigit(*s)) {
6381592Srgrimes			pad *= 10;
6391592Srgrimes			pad += *s++ - '0';
6401592Srgrimes		}
6411592Srgrimes		pad *= 10;
6421592Srgrimes		if (*s == '.' && isdigit(s[1])) {
6431592Srgrimes			pad += s[1] - '0';
6441592Srgrimes			s += 2;
6451592Srgrimes		}
6461592Srgrimes	}
6471592Srgrimes
6481592Srgrimes	puts(s);
6491592Srgrimes	/*
6501592Srgrimes	 * If no delay needed, or output speed is
6511592Srgrimes	 * not comprehensible, then don't try to delay.
6521592Srgrimes	 */
65315645Sjoerg	if (pad == 0 || ospeed <= 0)
6541592Srgrimes		return;
6551592Srgrimes
6561592Srgrimes	/*
6571592Srgrimes	 * Round up by a half a character frame, and then do the delay.
6581592Srgrimes	 * Too bad there are no user program accessible programmed delays.
6591592Srgrimes	 * Transmitting pad characters slows many terminals down and also
6601592Srgrimes	 * loads the system.
6611592Srgrimes	 */
66215645Sjoerg	pad = (pad * ospeed + 50000) / 100000;
66315645Sjoerg	while (pad--)
6641592Srgrimes		putchr(*PC);
6651592Srgrimes}
6661592Srgrimes
66715645Sjoergstatic void
66890301Simpputs(const char *s)
6691592Srgrimes{
6701592Srgrimes	while (*s)
6711592Srgrimes		putchr(*s++);
6721592Srgrimes}
6731592Srgrimes
6741592Srgrimeschar	outbuf[OBUFSIZ];
6751592Srgrimesint	obufcnt = 0;
6761592Srgrimes
67715645Sjoergstatic void
67890301Simpputchr(int cc)
6791592Srgrimes{
6801592Srgrimes	char c;
6811592Srgrimes
6821592Srgrimes	c = cc;
6831592Srgrimes	if (!NP) {
6841592Srgrimes		c |= partab[c&0177] & 0200;
6851592Srgrimes		if (OP)
6861592Srgrimes			c ^= 0200;
6871592Srgrimes	}
6881592Srgrimes	if (!UB) {
6891592Srgrimes		outbuf[obufcnt++] = c;
6901592Srgrimes		if (obufcnt >= OBUFSIZ)
6911592Srgrimes			oflush();
6921592Srgrimes	} else
6931592Srgrimes		write(STDOUT_FILENO, &c, 1);
6941592Srgrimes}
6951592Srgrimes
69615645Sjoergstatic void
69790301Simpoflush(void)
6981592Srgrimes{
6991592Srgrimes	if (obufcnt)
7001592Srgrimes		write(STDOUT_FILENO, outbuf, obufcnt);
7011592Srgrimes	obufcnt = 0;
7021592Srgrimes}
7031592Srgrimes
70415645Sjoergstatic void
70590301Simpprompt(void)
7061592Srgrimes{
7071592Srgrimes
7081592Srgrimes	putf(LM);
7091592Srgrimes	if (CO)
7101592Srgrimes		putchr('\n');
7111592Srgrimes}
7121592Srgrimes
71322208Sdavidn
71422208Sdavidnstatic char *
71590301Simpgetline(int fd)
71622208Sdavidn{
71722208Sdavidn	int i = 0;
71822208Sdavidn	static char linebuf[512];
71922208Sdavidn
72022208Sdavidn	/*
72122208Sdavidn	 * This is certainly slow, but it avoids having to include
72222208Sdavidn	 * stdio.h unnecessarily. Issue files should be small anyway.
72322208Sdavidn	 */
72422208Sdavidn	while (i < (sizeof linebuf - 3) && read(fd, linebuf+i, 1)==1) {
72522208Sdavidn		if (linebuf[i] == '\n') {
72622208Sdavidn			/* Don't rely on newline mode, assume raw */
72722208Sdavidn			linebuf[i++] = '\r';
72822208Sdavidn			linebuf[i++] = '\n';
72922208Sdavidn			linebuf[i] = '\0';
73022208Sdavidn			return linebuf;
73122208Sdavidn		}
73222208Sdavidn		++i;
73322208Sdavidn	}
73422208Sdavidn	linebuf[i] = '\0';
73522208Sdavidn	return i ? linebuf : 0;
73622208Sdavidn}
73722208Sdavidn
73815645Sjoergstatic void
73990301Simpputf(const char *cp)
7401592Srgrimes{
7411592Srgrimes	extern char editedhost[];
7421592Srgrimes	time_t t;
7431592Srgrimes	char *slash, db[100];
7441592Srgrimes
74522199Sdavidn	static struct utsname kerninfo;
74622199Sdavidn
74722199Sdavidn	if (!*kerninfo.sysname)
74822199Sdavidn		uname(&kerninfo);
74922199Sdavidn
7501592Srgrimes	while (*cp) {
7511592Srgrimes		if (*cp != '%') {
7521592Srgrimes			putchr(*cp++);
7531592Srgrimes			continue;
7541592Srgrimes		}
7551592Srgrimes		switch (*++cp) {
7561592Srgrimes
7571592Srgrimes		case 't':
75815645Sjoerg			slash = strrchr(ttyn, '/');
7591592Srgrimes			if (slash == (char *) 0)
7601592Srgrimes				puts(ttyn);
7611592Srgrimes			else
7621592Srgrimes				puts(&slash[1]);
7631592Srgrimes			break;
7641592Srgrimes
7651592Srgrimes		case 'h':
7661592Srgrimes			puts(editedhost);
7671592Srgrimes			break;
7681592Srgrimes
7691592Srgrimes		case 'd': {
77015645Sjoerg			t = (time_t)0;
7711592Srgrimes			(void)time(&t);
77215645Sjoerg			if (Lo)
77315645Sjoerg				(void)setlocale(LC_TIME, Lo);
77477874Syar			(void)strftime(db, sizeof(db), DF, localtime(&t));
7751592Srgrimes			puts(db);
7769875Sjkh			break;
77715645Sjoerg
77815645Sjoerg		case 's':
77915645Sjoerg			puts(kerninfo.sysname);
78015645Sjoerg			break;
78115645Sjoerg
78215645Sjoerg		case 'm':
78315645Sjoerg			puts(kerninfo.machine);
78415645Sjoerg			break;
78515645Sjoerg
78615645Sjoerg		case 'r':
78715645Sjoerg			puts(kerninfo.release);
78815645Sjoerg			break;
78915645Sjoerg
79015645Sjoerg		case 'v':
79115645Sjoerg			puts(kerninfo.version);
79215645Sjoerg			break;
7931592Srgrimes		}
7941592Srgrimes
7951592Srgrimes		case '%':
7961592Srgrimes			putchr('%');
7971592Srgrimes			break;
7981592Srgrimes		}
7991592Srgrimes		cp++;
8001592Srgrimes	}
8011592Srgrimes}
802116164Syar
803116164Syar/*
804116164Syar * Read a gettytab database entry and perform necessary quirks.
805116164Syar */
806116164Syarstatic void
807116533Syardogettytab()
808116164Syar{
809116164Syar
810116533Syar	/* Read the database entry. */
811116164Syar	gettable(tname, tabent);
812116164Syar
813116164Syar	/*
814116164Syar	 * Avoid inheriting the parity values from the default entry
815116164Syar	 * if any of them is set in the current entry.
816116164Syar	 * Mixing different parity settings is unreasonable.
817116164Syar	 */
818116164Syar	if (OPset || EPset || APset || NPset)
819116164Syar		OPset = EPset = APset = NPset = 1;
820116164Syar
821116533Syar	/* Fill in default values for unset capabilities. */
822116164Syar	setdefaults();
823116164Syar}
824