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
441592Srgrimes#endif /* not lint */
45216582Scharnier#include <sys/cdefs.h>
46216582Scharnier__FBSDID("$FreeBSD$");
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
70144716Sstefanf#include "gettytab.h"
7191216Sbde#include "extern.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{
430135941Simp	int i;
43122208Sdavidn	int failopenlogged = 0;
43222208Sdavidn
433135941Simp	while ((i = open(tty, flags)) == -1)
43422208Sdavidn	{
435135941Simp		if (!failopenlogged) {
43690302Simp			syslog(LOG_ERR, "open %s: %m", tty);
43722208Sdavidn			failopenlogged = 1;
43822208Sdavidn		}
43922208Sdavidn		sleep(60);
44022208Sdavidn	}
441135941Simp	if (login_tty(i) < 0) {
442135941Simp		if (daemon(0,0) < 0) {
443135941Simp			syslog(LOG_ERR,"daemon: %m");
444135941Simp			close(i);
445135941Simp			return 0;
44668888Sjwd		}
447135941Simp		if (login_tty(i) < 0) {
448135941Simp			syslog(LOG_ERR, "login_tty %s: %m", tty);
449135941Simp			close(i);
450135941Simp			return 0;
451135941Simp		}
45222208Sdavidn	}
453135941Simp	return 1;
45422208Sdavidn}
45522208Sdavidn
45622208Sdavidnstatic void
457214680Seddefttymode(void)
45822208Sdavidn{
459214680Sed	struct termios def;
460116533Syar
461116533Syar	/* Start with default tty settings. */
46222208Sdavidn	if (tcgetattr(STDIN_FILENO, &tmode) < 0) {
46322208Sdavidn		syslog(LOG_ERR, "tcgetattr %s: %m", ttyn);
46422208Sdavidn		exit(1);
46522208Sdavidn	}
466116533Syar	omode = tmode; /* fill c_cc for dogettytab() */
467116533Syar	dogettytab();
468116533Syar	/*
469116533Syar	 * Don't rely on the driver too much, and initialize crucial
470116533Syar	 * things according to <sys/ttydefaults.h>.  Avoid clobbering
471116533Syar	 * the c_cc[] settings however, the console drivers might wish
472116533Syar	 * to leave their idea of the preferred VERASE key value
473116533Syar	 * there.
474116533Syar	 */
475214680Sed	cfmakesane(&def);
476214680Sed	tmode.c_iflag = def.c_iflag;
477214680Sed	tmode.c_oflag = def.c_oflag;
478214680Sed	tmode.c_lflag = def.c_lflag;
479214680Sed	tmode.c_cflag = def.c_cflag;
480116533Syar	if (NC)
481116533Syar		tmode.c_cflag |= CLOCAL;
482116533Syar	omode = tmode;
48322208Sdavidn}
48422208Sdavidn
48522208Sdavidnstatic void
486116164Syarsetttymode(int raw)
48722208Sdavidn{
48822208Sdavidn	int off = 0;
48922208Sdavidn
49022208Sdavidn	(void)tcflush(STDIN_FILENO, TCIOFLUSH);	/* clear out the crap */
49122208Sdavidn	ioctl(STDIN_FILENO, FIONBIO, &off);	/* turn off non-blocking mode */
49222208Sdavidn	ioctl(STDIN_FILENO, FIOASYNC, &off);	/* ditto for async mode */
49322208Sdavidn
49422208Sdavidn	if (IS)
49522208Sdavidn		cfsetispeed(&tmode, speed(IS));
49622208Sdavidn	else if (SP)
49722208Sdavidn		cfsetispeed(&tmode, speed(SP));
49822208Sdavidn	if (OS)
49922208Sdavidn		cfsetospeed(&tmode, speed(OS));
50022208Sdavidn	else if (SP)
50122208Sdavidn		cfsetospeed(&tmode, speed(SP));
50256725Sbde	set_flags(0);
50322208Sdavidn	setchars();
50422208Sdavidn	if (raw)
50522208Sdavidn		cfmakeraw(&tmode);
50622208Sdavidn	if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
50722208Sdavidn		syslog(LOG_ERR, "tcsetattr %s: %m", ttyn);
50822208Sdavidn		exit(1);
50922208Sdavidn	}
51022208Sdavidn}
51122208Sdavidn
51222208Sdavidn
51322208Sdavidnstatic int
51490301Simpgetname(void)
5151592Srgrimes{
51690301Simp	int c;
51790301Simp	char *np;
51819697Spst	unsigned char cs;
51922208Sdavidn	int ppp_state = 0;
52019697Spst	int ppp_connection = 0;
5211592Srgrimes
5221592Srgrimes	/*
5231592Srgrimes	 * Interrupt may happen if we use CBREAK mode
5241592Srgrimes	 */
5251592Srgrimes	if (setjmp(intrupt)) {
5261592Srgrimes		signal(SIGINT, SIG_IGN);
5271592Srgrimes		return (0);
5281592Srgrimes	}
5291592Srgrimes	signal(SIGINT, interrupt);
53056725Sbde	set_flags(1);
5311592Srgrimes	prompt();
5322286Sjkh	oflush();
5331592Srgrimes	if (PF > 0) {
5341592Srgrimes		sleep(PF);
5351592Srgrimes		PF = 0;
5361592Srgrimes	}
53722208Sdavidn	if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
53815645Sjoerg		syslog(LOG_ERR, "%s: %m", ttyn);
53915645Sjoerg		exit(1);
54015645Sjoerg	}
5411592Srgrimes	crmod = digit = lower = upper = 0;
5421592Srgrimes	np = name;
5431592Srgrimes	for (;;) {
5441592Srgrimes		oflush();
5451592Srgrimes		if (read(STDIN_FILENO, &cs, 1) <= 0)
5461592Srgrimes			exit(0);
5471592Srgrimes		if ((c = cs&0177) == 0)
5481592Srgrimes			return (0);
54919697Spst
55019697Spst		/* PPP detection state machine..
55119697Spst		   Look for sequences:
55219697Spst		   PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or
55319697Spst		   PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC)
55419697Spst		   See RFC1662.
55519697Spst		   Derived from code from Michael Hancock, <michaelh@cet.co.jp>
55619697Spst		   and Erik 'PPP' Olson, <eriko@wrq.com>
55719697Spst		 */
55819697Spst
55919697Spst		if (PP && (cs == PPP_FRAME)) {
56019697Spst			ppp_state = 1;
56119697Spst		} else if (ppp_state == 1 && cs == PPP_STATION) {
56219697Spst			ppp_state = 2;
56319697Spst		} else if (ppp_state == 2 && cs == PPP_ESCAPE) {
56419697Spst			ppp_state = 3;
56519697Spst		} else if ((ppp_state == 2 && cs == PPP_CONTROL)
56619697Spst			|| (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) {
56719697Spst			ppp_state = 4;
56819697Spst		} else if (ppp_state == 4 && cs == PPP_LCP_HI) {
56919697Spst			ppp_state = 5;
57019697Spst		} else if (ppp_state == 5 && cs == PPP_LCP_LOW) {
57119697Spst			ppp_connection = 1;
57219697Spst			break;
57319697Spst		} else {
57419697Spst			ppp_state = 0;
57519697Spst		}
57619697Spst
57715645Sjoerg		if (c == EOT || c == CTRL('d'))
578115900Syar			exit(0);
57922211Sdavidn		if (c == '\r' || c == '\n' || np >= &name[sizeof name-1]) {
5801592Srgrimes			putf("\r\n");
5811592Srgrimes			break;
5821592Srgrimes		}
5831592Srgrimes		if (islower(c))
5841592Srgrimes			lower = 1;
5851592Srgrimes		else if (isupper(c))
5861592Srgrimes			upper = 1;
5872286Sjkh		else if (c == ERASE || c == '\b' || c == 0177) {
5881592Srgrimes			if (np > name) {
5891592Srgrimes				np--;
59015645Sjoerg				if (cfgetospeed(&tmode) >= 1200)
5911592Srgrimes					puts("\b \b");
5921592Srgrimes				else
5931592Srgrimes					putchr(cs);
5941592Srgrimes			}
5951592Srgrimes			continue;
59615645Sjoerg		} else if (c == KILL || c == CTRL('u')) {
5971592Srgrimes			putchr('\r');
59815645Sjoerg			if (cfgetospeed(&tmode) < 1200)
5991592Srgrimes				putchr('\n');
6001592Srgrimes			/* this is the way they do it down under ... */
6011592Srgrimes			else if (np > name)
6021592Srgrimes				puts("                                     \r");
6031592Srgrimes			prompt();
604115900Syar			digit = lower = upper = 0;
6051592Srgrimes			np = name;
6061592Srgrimes			continue;
6071592Srgrimes		} else if (isdigit(c))
608116154Syar			digit = 1;
6091592Srgrimes		if (IG && (c <= ' ' || c > 0176))
6101592Srgrimes			continue;
6111592Srgrimes		*np++ = c;
6121592Srgrimes		putchr(cs);
6131592Srgrimes	}
6141592Srgrimes	signal(SIGINT, SIG_IGN);
6151592Srgrimes	*np = 0;
6161592Srgrimes	if (c == '\r')
6171592Srgrimes		crmod = 1;
61815645Sjoerg	if ((upper && !lower && !LC) || UC)
6191592Srgrimes		for (np = name; *np; np++)
6201592Srgrimes			if (isupper(*np))
6211592Srgrimes				*np = tolower(*np);
62219697Spst	return (1 + ppp_connection);
6231592Srgrimes}
6241592Srgrimes
62515645Sjoergstatic void
62690301Simpputpad(const char *s)
6271592Srgrimes{
62890301Simp	int pad = 0;
62915645Sjoerg	speed_t ospeed = cfgetospeed(&tmode);
6301592Srgrimes
6311592Srgrimes	if (isdigit(*s)) {
6321592Srgrimes		while (isdigit(*s)) {
6331592Srgrimes			pad *= 10;
6341592Srgrimes			pad += *s++ - '0';
6351592Srgrimes		}
6361592Srgrimes		pad *= 10;
6371592Srgrimes		if (*s == '.' && isdigit(s[1])) {
6381592Srgrimes			pad += s[1] - '0';
6391592Srgrimes			s += 2;
6401592Srgrimes		}
6411592Srgrimes	}
6421592Srgrimes
6431592Srgrimes	puts(s);
6441592Srgrimes	/*
6451592Srgrimes	 * If no delay needed, or output speed is
6461592Srgrimes	 * not comprehensible, then don't try to delay.
6471592Srgrimes	 */
64815645Sjoerg	if (pad == 0 || ospeed <= 0)
6491592Srgrimes		return;
6501592Srgrimes
6511592Srgrimes	/*
6521592Srgrimes	 * Round up by a half a character frame, and then do the delay.
6531592Srgrimes	 * Too bad there are no user program accessible programmed delays.
6541592Srgrimes	 * Transmitting pad characters slows many terminals down and also
6551592Srgrimes	 * loads the system.
6561592Srgrimes	 */
65715645Sjoerg	pad = (pad * ospeed + 50000) / 100000;
65815645Sjoerg	while (pad--)
6591592Srgrimes		putchr(*PC);
6601592Srgrimes}
6611592Srgrimes
66215645Sjoergstatic void
66390301Simpputs(const char *s)
6641592Srgrimes{
6651592Srgrimes	while (*s)
6661592Srgrimes		putchr(*s++);
6671592Srgrimes}
6681592Srgrimes
6691592Srgrimeschar	outbuf[OBUFSIZ];
6701592Srgrimesint	obufcnt = 0;
6711592Srgrimes
67215645Sjoergstatic void
67390301Simpputchr(int cc)
6741592Srgrimes{
6751592Srgrimes	char c;
6761592Srgrimes
6771592Srgrimes	c = cc;
6781592Srgrimes	if (!NP) {
6791592Srgrimes		c |= partab[c&0177] & 0200;
6801592Srgrimes		if (OP)
6811592Srgrimes			c ^= 0200;
6821592Srgrimes	}
6831592Srgrimes	if (!UB) {
6841592Srgrimes		outbuf[obufcnt++] = c;
6851592Srgrimes		if (obufcnt >= OBUFSIZ)
6861592Srgrimes			oflush();
6871592Srgrimes	} else
6881592Srgrimes		write(STDOUT_FILENO, &c, 1);
6891592Srgrimes}
6901592Srgrimes
69115645Sjoergstatic void
69290301Simpoflush(void)
6931592Srgrimes{
6941592Srgrimes	if (obufcnt)
6951592Srgrimes		write(STDOUT_FILENO, outbuf, obufcnt);
6961592Srgrimes	obufcnt = 0;
6971592Srgrimes}
6981592Srgrimes
69915645Sjoergstatic void
70090301Simpprompt(void)
7011592Srgrimes{
7021592Srgrimes
7031592Srgrimes	putf(LM);
7041592Srgrimes	if (CO)
7051592Srgrimes		putchr('\n');
7061592Srgrimes}
7071592Srgrimes
70822208Sdavidn
70922208Sdavidnstatic char *
71090301Simpgetline(int fd)
71122208Sdavidn{
71222208Sdavidn	int i = 0;
71322208Sdavidn	static char linebuf[512];
71422208Sdavidn
71522208Sdavidn	/*
71622208Sdavidn	 * This is certainly slow, but it avoids having to include
71722208Sdavidn	 * stdio.h unnecessarily. Issue files should be small anyway.
71822208Sdavidn	 */
71922208Sdavidn	while (i < (sizeof linebuf - 3) && read(fd, linebuf+i, 1)==1) {
72022208Sdavidn		if (linebuf[i] == '\n') {
72122208Sdavidn			/* Don't rely on newline mode, assume raw */
72222208Sdavidn			linebuf[i++] = '\r';
72322208Sdavidn			linebuf[i++] = '\n';
72422208Sdavidn			linebuf[i] = '\0';
72522208Sdavidn			return linebuf;
72622208Sdavidn		}
72722208Sdavidn		++i;
72822208Sdavidn	}
72922208Sdavidn	linebuf[i] = '\0';
73022208Sdavidn	return i ? linebuf : 0;
73122208Sdavidn}
73222208Sdavidn
73315645Sjoergstatic void
73490301Simpputf(const char *cp)
7351592Srgrimes{
7361592Srgrimes	extern char editedhost[];
7371592Srgrimes	time_t t;
7381592Srgrimes	char *slash, db[100];
7391592Srgrimes
74022199Sdavidn	static struct utsname kerninfo;
74122199Sdavidn
74222199Sdavidn	if (!*kerninfo.sysname)
74322199Sdavidn		uname(&kerninfo);
74422199Sdavidn
7451592Srgrimes	while (*cp) {
7461592Srgrimes		if (*cp != '%') {
7471592Srgrimes			putchr(*cp++);
7481592Srgrimes			continue;
7491592Srgrimes		}
7501592Srgrimes		switch (*++cp) {
7511592Srgrimes
7521592Srgrimes		case 't':
75315645Sjoerg			slash = strrchr(ttyn, '/');
7541592Srgrimes			if (slash == (char *) 0)
7551592Srgrimes				puts(ttyn);
7561592Srgrimes			else
7571592Srgrimes				puts(&slash[1]);
7581592Srgrimes			break;
7591592Srgrimes
7601592Srgrimes		case 'h':
7611592Srgrimes			puts(editedhost);
7621592Srgrimes			break;
7631592Srgrimes
7641592Srgrimes		case 'd': {
76515645Sjoerg			t = (time_t)0;
7661592Srgrimes			(void)time(&t);
76715645Sjoerg			if (Lo)
76815645Sjoerg				(void)setlocale(LC_TIME, Lo);
76977874Syar			(void)strftime(db, sizeof(db), DF, localtime(&t));
7701592Srgrimes			puts(db);
7719875Sjkh			break;
77215645Sjoerg
77315645Sjoerg		case 's':
77415645Sjoerg			puts(kerninfo.sysname);
77515645Sjoerg			break;
77615645Sjoerg
77715645Sjoerg		case 'm':
77815645Sjoerg			puts(kerninfo.machine);
77915645Sjoerg			break;
78015645Sjoerg
78115645Sjoerg		case 'r':
78215645Sjoerg			puts(kerninfo.release);
78315645Sjoerg			break;
78415645Sjoerg
78515645Sjoerg		case 'v':
78615645Sjoerg			puts(kerninfo.version);
78715645Sjoerg			break;
7881592Srgrimes		}
7891592Srgrimes
7901592Srgrimes		case '%':
7911592Srgrimes			putchr('%');
7921592Srgrimes			break;
7931592Srgrimes		}
7941592Srgrimes		cp++;
7951592Srgrimes	}
7961592Srgrimes}
797116164Syar
798116164Syar/*
799116164Syar * Read a gettytab database entry and perform necessary quirks.
800116164Syar */
801116164Syarstatic void
802216582Scharnierdogettytab(void)
803116164Syar{
804116164Syar
805116533Syar	/* Read the database entry. */
806116164Syar	gettable(tname, tabent);
807116164Syar
808116164Syar	/*
809116164Syar	 * Avoid inheriting the parity values from the default entry
810116164Syar	 * if any of them is set in the current entry.
811116164Syar	 * Mixing different parity settings is unreasonable.
812116164Syar	 */
813116164Syar	if (OPset || EPset || APset || NPset)
814116164Syar		OPset = EPset = APset = NPset = 1;
815116164Syar
816116533Syar	/* Fill in default values for unset capabilities. */
817116164Syar	setdefaults();
818116164Syar}
819