main.c revision 77874
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 77874 2001-06-07 13:53:23Z yar $";
461592Srgrimes#endif /* not lint */
471592Srgrimes
481592Srgrimes#include <sys/param.h>
491592Srgrimes#include <sys/stat.h>
5015645Sjoerg#include <sys/ioctl.h>
5115645Sjoerg#include <sys/resource.h>
5215645Sjoerg#include <sys/ttydefaults.h>
5315645Sjoerg#include <sys/utsname.h>
5466907Swollman
5531331Scharnier#include <ctype.h>
5615645Sjoerg#include <errno.h>
572286Sjkh#include <fcntl.h>
5831331Scharnier#include <locale.h>
5915645Sjoerg#include <libutil.h>
6031331Scharnier#include <signal.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
701592Srgrimes#include "gettytab.h"
711592Srgrimes#include "pathnames.h"
7215645Sjoerg#include "extern.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
9315645Sjoergstruct termios tmode, omode;
9415645Sjoerg
951592Srgrimesint crmod, digit, lower, upper;
961592Srgrimes
971592Srgrimeschar	hostname[MAXHOSTNAMELEN];
9822400Sdavidnchar	name[MAXLOGNAME*3];
991592Srgrimeschar	dev[] = _PATH_DEV;
1001592Srgrimeschar	ttyn[32];
1011592Srgrimes
1021592Srgrimes#define	OBUFSIZ		128
1031592Srgrimes#define	TABBUFSIZ	512
1041592Srgrimes
1051592Srgrimeschar	defent[TABBUFSIZ];
1061592Srgrimeschar	tabent[TABBUFSIZ];
1071592Srgrimes
1081592Srgrimeschar	*env[128];
1091592Srgrimes
1101592Srgrimeschar partab[] = {
1111592Srgrimes	0001,0201,0201,0001,0201,0001,0001,0201,
1121592Srgrimes	0202,0004,0003,0205,0005,0206,0201,0001,
1131592Srgrimes	0201,0001,0001,0201,0001,0201,0201,0001,
1141592Srgrimes	0001,0201,0201,0001,0201,0001,0001,0201,
1151592Srgrimes	0200,0000,0000,0200,0000,0200,0200,0000,
1161592Srgrimes	0000,0200,0200,0000,0200,0000,0000,0200,
1171592Srgrimes	0000,0200,0200,0000,0200,0000,0000,0200,
1181592Srgrimes	0200,0000,0000,0200,0000,0200,0200,0000,
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	0000,0200,0200,0000,0200,0000,0000,0200,
1241592Srgrimes	0200,0000,0000,0200,0000,0200,0200,0000,
1251592Srgrimes	0200,0000,0000,0200,0000,0200,0200,0000,
1261592Srgrimes	0000,0200,0200,0000,0200,0000,0000,0201
1271592Srgrimes};
1281592Srgrimes
12915645Sjoerg#define	ERASE	tmode.c_cc[VERASE]
13015645Sjoerg#define	KILL	tmode.c_cc[VKILL]
13115645Sjoerg#define	EOT	tmode.c_cc[VEOF]
1321592Srgrimes
13340083Sjkh#define	puts	Gputs
13440083Sjkh
13515645Sjoergstatic void	dingdong __P((int));
13615645Sjoergstatic int	getname __P((void));
13715645Sjoergstatic void	interrupt __P((int));
13815645Sjoergstatic void	oflush __P((void));
13915645Sjoergstatic void	prompt __P((void));
14015645Sjoergstatic void	putchr __P((int));
14115645Sjoergstatic void	putf __P((const char *));
14215645Sjoergstatic void	putpad __P((const char *));
14315645Sjoergstatic void	puts __P((const char *));
14415645Sjoergstatic void	timeoverrun __P((int));
14522208Sdavidnstatic char	*getline __P((int));
14622208Sdavidnstatic void	setttymode __P((const char *, int));
14722208Sdavidnstatic void	setdefttymode __P((const char *));
14822208Sdavidnstatic int	opentty __P((const char *, int));
14915645Sjoerg
15015645Sjoergint		main __P((int, char **));
15115645Sjoerg
15222208Sdavidnjmp_buf timeout;
15322208Sdavidn
1541592Srgrimesstatic void
15515645Sjoergdingdong(signo)
15615645Sjoerg	int signo;
1571592Srgrimes{
1581592Srgrimes	alarm(0);
1591592Srgrimes	longjmp(timeout, 1);
1601592Srgrimes}
1611592Srgrimes
1621592Srgrimesjmp_buf	intrupt;
1631592Srgrimes
1641592Srgrimesstatic void
16515645Sjoerginterrupt(signo)
16615645Sjoerg	int signo;
1671592Srgrimes{
1681592Srgrimes	longjmp(intrupt, 1);
1691592Srgrimes}
1701592Srgrimes
17115645Sjoerg/*
17215645Sjoerg * Action to take when getty is running too long.
17315645Sjoerg */
17415645Sjoergstatic void
17515645Sjoergtimeoverrun(signo)
17615645Sjoerg	int signo;
17715645Sjoerg{
17815645Sjoerg
17931331Scharnier	syslog(LOG_ERR, "getty exiting due to excessive running time");
18015645Sjoerg	exit(1);
18115645Sjoerg}
18215645Sjoerg
18315645Sjoergint
1841592Srgrimesmain(argc, argv)
1851592Srgrimes	int argc;
1862286Sjkh	char **argv;
1871592Srgrimes{
1882286Sjkh	extern	char **environ;
18915645Sjoerg	const char *tname;
19022491Sdavidn	int first_sleep = 1, first_time = 1;
19115645Sjoerg	struct rlimit limit;
19219697Spst	int rval;
1931592Srgrimes
1941592Srgrimes	signal(SIGINT, SIG_IGN);
1952391Sache	signal(SIGQUIT, SIG_IGN);
1962286Sjkh
19715645Sjoerg	openlog("getty", LOG_ODELAY|LOG_CONS|LOG_PID, LOG_AUTH);
19845422Sbrian	gethostname(hostname, sizeof(hostname) - 1);
19945422Sbrian	hostname[sizeof(hostname) - 1] = '\0';
2001592Srgrimes	if (hostname[0] == '\0')
2011592Srgrimes		strcpy(hostname, "Amnesiac");
20215645Sjoerg
2031592Srgrimes	/*
20415645Sjoerg	 * Limit running time to deal with broken or dead lines.
20515645Sjoerg	 */
20615645Sjoerg	(void)signal(SIGXCPU, timeoverrun);
20715645Sjoerg	limit.rlim_max = RLIM_INFINITY;
20815645Sjoerg	limit.rlim_cur = GETTY_TIMEOUT;
20915645Sjoerg	(void)setrlimit(RLIMIT_CPU, &limit);
21015645Sjoerg
21122208Sdavidn	gettable("default", defent);
21222208Sdavidn	gendefaults();
21322208Sdavidn	tname = "default";
21422208Sdavidn	if (argc > 1)
21522208Sdavidn		tname = argv[1];
21622208Sdavidn
21715645Sjoerg	/*
2181592Srgrimes	 * The following is a work around for vhangup interactions
2191592Srgrimes	 * which cause great problems getting window systems started.
2201592Srgrimes	 * If the tty line is "-", we do the old style getty presuming
2218870Srgrimes	 * that the file descriptors are already set up for us.
2221592Srgrimes	 * J. Gettys - MIT Project Athena.
2231592Srgrimes	 */
2241592Srgrimes	if (argc <= 2 || strcmp(argv[2], "-") == 0)
22522208Sdavidn	    strcpy(ttyn, ttyname(STDIN_FILENO));
2261592Srgrimes	else {
2271592Srgrimes	    strcpy(ttyn, dev);
2281592Srgrimes	    strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
2291592Srgrimes	    if (strcmp(argv[0], "+") != 0) {
2301592Srgrimes		chown(ttyn, 0, 0);
2311592Srgrimes		chmod(ttyn, 0600);
2321592Srgrimes		revoke(ttyn);
23322208Sdavidn
23422208Sdavidn		gettable(tname, tabent);
23522208Sdavidn
23622208Sdavidn		/* Init modem sequence has been specified
23722208Sdavidn		 */
23822208Sdavidn		if (IC) {
23922208Sdavidn			if (!opentty(ttyn, O_RDWR|O_NONBLOCK))
24022208Sdavidn				exit(1);
24122208Sdavidn			setdefttymode(tname);
24222208Sdavidn			if (getty_chat(IC, CT, DC) > 0) {
24322208Sdavidn				syslog(LOG_ERR, "modem init problem on %s", ttyn);
24422491Sdavidn				(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
24522208Sdavidn				exit(1);
2461592Srgrimes			}
2471592Srgrimes		}
24822208Sdavidn
24922208Sdavidn		if (AC) {
25022208Sdavidn			int i, rfds;
25122208Sdavidn			struct timeval timeout;
25222208Sdavidn
25322208Sdavidn			if (!opentty(ttyn, O_RDWR|O_NONBLOCK))
25422208Sdavidn				exit(1);
25522208Sdavidn        		setdefttymode(tname);
25622208Sdavidn        		rfds = 1 << 0;	/* FD_SET */
25722208Sdavidn        		timeout.tv_sec = RT;
25822208Sdavidn        		timeout.tv_usec = 0;
25922208Sdavidn        		i = select(32, (fd_set*)&rfds, (fd_set*)NULL,
26022208Sdavidn        			       (fd_set*)NULL, RT ? &timeout : NULL);
26122208Sdavidn        		if (i < 0) {
26222208Sdavidn				syslog(LOG_ERR, "select %s: %m", ttyn);
26322208Sdavidn			} else if (i == 0) {
26422208Sdavidn				syslog(LOG_NOTICE, "recycle tty %s", ttyn);
26522491Sdavidn				(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
26622208Sdavidn				exit(0);  /* recycle for init */
26722208Sdavidn			}
26822208Sdavidn			i = getty_chat(AC, CT, DC);
26922208Sdavidn			if (i > 0) {
27022208Sdavidn				syslog(LOG_ERR, "modem answer problem on %s", ttyn);
27122491Sdavidn				(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
27222208Sdavidn				exit(1);
27322208Sdavidn			}
27464076Snsayer		} else { /* maybe blocking open */
27564076Snsayer			if (!opentty(ttyn, O_RDWR | (NC ? O_NONBLOCK : 0 )))
27622208Sdavidn				exit(1);
27722208Sdavidn		}
2781592Srgrimes	    }
2791592Srgrimes	}
2801592Srgrimes
28115645Sjoerg	/* Start with default tty settings */
28222208Sdavidn	if (tcgetattr(STDIN_FILENO, &tmode) < 0) {
28322208Sdavidn		syslog(LOG_ERR, "tcgetattr %s: %m", ttyn);
28415645Sjoerg		exit(1);
28515645Sjoerg	}
28615645Sjoerg	/*
28715645Sjoerg	 * Don't rely on the driver too much, and initialize crucial
28815645Sjoerg	 * things according to <sys/ttydefaults.h>.  Avoid clobbering
28915645Sjoerg	 * the c_cc[] settings however, the console drivers might wish
29015645Sjoerg	 * to leave their idea of the preferred VERASE key value
29115645Sjoerg	 * there.
29215645Sjoerg	 */
29315645Sjoerg	tmode.c_iflag = TTYDEF_IFLAG;
29415645Sjoerg	tmode.c_oflag = TTYDEF_OFLAG;
29515645Sjoerg	tmode.c_lflag = TTYDEF_LFLAG;
29615645Sjoerg	tmode.c_cflag = TTYDEF_CFLAG;
29764076Snsayer	tmode.c_cflag |= (NC ? CLOCAL : 0);
29815645Sjoerg	omode = tmode;
29915645Sjoerg
3001592Srgrimes	for (;;) {
3011592Srgrimes
30222491Sdavidn		/*
30322491Sdavidn		 * if a delay was specified then sleep for that
30422491Sdavidn		 * number of seconds before writing the initial prompt
30522491Sdavidn		 */
30622491Sdavidn		if (first_sleep && DE) {
30722491Sdavidn		    sleep(DE);
30822491Sdavidn		    /* remove any noise */
30922491Sdavidn		    (void)tcflush(STDIN_FILENO, TCIOFLUSH);
31022491Sdavidn		}
31122491Sdavidn		first_sleep = 0;
31222491Sdavidn
31322208Sdavidn		setttymode(tname, 0);
3141592Srgrimes		if (AB) {
3151592Srgrimes			tname = autobaud();
3161592Srgrimes			continue;
3171592Srgrimes		}
3181592Srgrimes		if (PS) {
3191592Srgrimes			tname = portselector();
3201592Srgrimes			continue;
3211592Srgrimes		}
3221592Srgrimes		if (CL && *CL)
3231592Srgrimes			putpad(CL);
3241592Srgrimes		edithost(HE);
32521120Smsmith
32622208Sdavidn		/* if this is the first time through this, and an
32722208Sdavidn		   issue file has been given, then send it */
32822208Sdavidn		if (first_time && IF) {
32922208Sdavidn			int fd;
33022208Sdavidn
33122208Sdavidn			if ((fd = open(IF, O_RDONLY)) != -1) {
33222208Sdavidn				char * cp;
33322208Sdavidn
33422208Sdavidn				while ((cp = getline(fd)) != NULL) {
33522208Sdavidn					  putf(cp);
33622208Sdavidn				}
33722208Sdavidn				close(fd);
33822208Sdavidn			}
33922208Sdavidn		}
34022491Sdavidn		first_time = 0;
34122208Sdavidn
3421592Srgrimes		if (IM && *IM)
3431592Srgrimes			putf(IM);
3441592Srgrimes		if (setjmp(timeout)) {
34515659Sache			cfsetispeed(&tmode, B0);
34615659Sache			cfsetospeed(&tmode, B0);
34722208Sdavidn			(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
3481592Srgrimes			exit(1);
3491592Srgrimes		}
3501592Srgrimes		if (TO) {
3511592Srgrimes			signal(SIGALRM, dingdong);
3521592Srgrimes			alarm(TO);
3531592Srgrimes		}
35445291Speter		if (AL) {
35545291Speter			const char *p = AL;
35645291Speter			char *q = name;
35745291Speter			int n = sizeof name;
35845291Speter
35945291Speter			while (*p && q < &name[sizeof name - 1]) {
36045291Speter				if (isupper(*p))
36145291Speter					upper = 1;
36245291Speter				else if (islower(*p))
36345291Speter					lower = 1;
36445291Speter				else if (isdigit(*p))
36545291Speter					digit++;
36645291Speter				*q++ = *p++;
36745291Speter			}
36845291Speter		} else
36945291Speter			rval = getname();
37045291Speter		if (rval == 2) {
37126415Sdavidn			oflush();
37226415Sdavidn			alarm(0);
37344615Sbrian			limit.rlim_max = RLIM_INFINITY;
37444615Sbrian			limit.rlim_cur = RLIM_INFINITY;
37544615Sbrian			(void)setrlimit(RLIMIT_CPU, &limit);
37619697Spst			execle(PP, "ppplogin", ttyn, (char *) 0, env);
37719697Spst			syslog(LOG_ERR, "%s: %m", PP);
37819697Spst			exit(1);
37945291Speter		} else if (rval || AL) {
3801592Srgrimes			register int i;
3811592Srgrimes
38215645Sjoerg			oflush();
3831592Srgrimes			alarm(0);
3841592Srgrimes			signal(SIGALRM, SIG_DFL);
3851592Srgrimes			if (name[0] == '-') {
3861592Srgrimes				puts("user names may not start with '-'.");
3871592Srgrimes				continue;
3881592Srgrimes			}
3891592Srgrimes			if (!(upper || lower || digit))
3901592Srgrimes				continue;
39156725Sbde			set_flags(2);
39215645Sjoerg			if (crmod) {
39315645Sjoerg				tmode.c_iflag |= ICRNL;
39415645Sjoerg				tmode.c_oflag |= ONLCR;
39515645Sjoerg			}
39615645Sjoerg#if REALLY_OLD_TTYS
39715645Sjoerg			if (upper || UC)
39815645Sjoerg				tmode.sg_flags |= LCASE;
39915645Sjoerg			if (lower || LC)
40015645Sjoerg				tmode.sg_flags &= ~LCASE;
40115645Sjoerg#endif
40222208Sdavidn			if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
40322208Sdavidn				syslog(LOG_ERR, "tcsetattr %s: %m", ttyn);
40415645Sjoerg				exit(1);
40515645Sjoerg			}
40615645Sjoerg			signal(SIGINT, SIG_DFL);
4071592Srgrimes			for (i = 0; environ[i] != (char *)0; i++)
4081592Srgrimes				env[i] = environ[i];
4091592Srgrimes			makeenv(&env[i]);
4101592Srgrimes
41115645Sjoerg			limit.rlim_max = RLIM_INFINITY;
41215645Sjoerg			limit.rlim_cur = RLIM_INFINITY;
41315645Sjoerg			(void)setrlimit(RLIMIT_CPU, &limit);
41445291Speter			execle(LO, "login", AL ? "-fp" : "-p", name,
41545291Speter			    (char *) 0, env);
4161592Srgrimes			syslog(LOG_ERR, "%s: %m", LO);
4171592Srgrimes			exit(1);
4181592Srgrimes		}
4191592Srgrimes		alarm(0);
4201592Srgrimes		signal(SIGALRM, SIG_DFL);
42115645Sjoerg		signal(SIGINT, SIG_IGN);
4221592Srgrimes		if (NX && *NX)
4231592Srgrimes			tname = NX;
4241592Srgrimes	}
4251592Srgrimes}
4261592Srgrimes
42715645Sjoergstatic int
42822208Sdavidnopentty(const char *ttyn, int flags)
42922208Sdavidn{
43022208Sdavidn	int i, j = 0;
43122208Sdavidn	int failopenlogged = 0;
43222208Sdavidn
43322208Sdavidn	while (j < 10 && (i = open(ttyn, flags)) == -1)
43422208Sdavidn	{
43522208Sdavidn		if (((j % 10) == 0) && (errno != ENXIO || !failopenlogged)) {
43622208Sdavidn			syslog(LOG_ERR, "open %s: %m", ttyn);
43722208Sdavidn			failopenlogged = 1;
43822208Sdavidn		}
43922208Sdavidn		j++;
44022208Sdavidn		sleep(60);
44122208Sdavidn	}
44222208Sdavidn	if (i == -1) {
44322208Sdavidn		syslog(LOG_ERR, "open %s: %m", ttyn);
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) {
45468888Sjwd				syslog(LOG_ERR, "login_tty %s: %m", ttyn);
45568888Sjwd				close(i);
45668888Sjwd				return 0;
45768888Sjwd			}
45868888Sjwd		}
45922208Sdavidn		return 1;
46022208Sdavidn	}
46122208Sdavidn}
46222208Sdavidn
46322208Sdavidnstatic void
46422208Sdavidnsetdefttymode(tname)
46522208Sdavidn	const char * tname;
46622208Sdavidn{
46722208Sdavidn	if (tcgetattr(STDIN_FILENO, &tmode) < 0) {
46822208Sdavidn		syslog(LOG_ERR, "tcgetattr %s: %m", ttyn);
46922208Sdavidn		exit(1);
47022208Sdavidn	}
47122208Sdavidn	tmode.c_iflag = TTYDEF_IFLAG;
47222208Sdavidn        tmode.c_oflag = TTYDEF_OFLAG;
47322208Sdavidn        tmode.c_lflag = TTYDEF_LFLAG;
47422208Sdavidn        tmode.c_cflag = TTYDEF_CFLAG;
47522208Sdavidn        omode = tmode;
47622208Sdavidn	setttymode(tname, 1);
47722208Sdavidn}
47822208Sdavidn
47922208Sdavidnstatic void
48022208Sdavidnsetttymode(tname, raw)
48122208Sdavidn	const char * tname;
48222208Sdavidn	int raw;
48322208Sdavidn{
48422208Sdavidn	int off = 0;
48522208Sdavidn
48622208Sdavidn	gettable(tname, tabent);
48722208Sdavidn	if (OPset || EPset || APset)
48822208Sdavidn		APset++, OPset++, EPset++;
48922208Sdavidn	setdefaults();
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
5141592Srgrimesgetname()
5151592Srgrimes{
5161592Srgrimes	register int c;
5171592Srgrimes	register 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'))
5781592Srgrimes			exit(1);
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();
6041592Srgrimes			np = name;
6051592Srgrimes			continue;
6061592Srgrimes		} else if (isdigit(c))
6071592Srgrimes			digit++;
6081592Srgrimes		if (IG && (c <= ' ' || c > 0176))
6091592Srgrimes			continue;
6101592Srgrimes		*np++ = c;
6111592Srgrimes		putchr(cs);
6121592Srgrimes	}
6131592Srgrimes	signal(SIGINT, SIG_IGN);
6141592Srgrimes	*np = 0;
6151592Srgrimes	if (c == '\r')
6161592Srgrimes		crmod = 1;
61715645Sjoerg	if ((upper && !lower && !LC) || UC)
6181592Srgrimes		for (np = name; *np; np++)
6191592Srgrimes			if (isupper(*np))
6201592Srgrimes				*np = tolower(*np);
62119697Spst	return (1 + ppp_connection);
6221592Srgrimes}
6231592Srgrimes
62415645Sjoergstatic void
6251592Srgrimesputpad(s)
62615645Sjoerg	register const char *s;
6271592Srgrimes{
6281592Srgrimes	register 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
6631592Srgrimesputs(s)
66415645Sjoerg	register const char *s;
6651592Srgrimes{
6661592Srgrimes	while (*s)
6671592Srgrimes		putchr(*s++);
6681592Srgrimes}
6691592Srgrimes
6701592Srgrimeschar	outbuf[OBUFSIZ];
6711592Srgrimesint	obufcnt = 0;
6721592Srgrimes
67315645Sjoergstatic void
6741592Srgrimesputchr(cc)
67515645Sjoerg	int cc;
6761592Srgrimes{
6771592Srgrimes	char c;
6781592Srgrimes
6791592Srgrimes	c = cc;
6801592Srgrimes	if (!NP) {
6811592Srgrimes		c |= partab[c&0177] & 0200;
6821592Srgrimes		if (OP)
6831592Srgrimes			c ^= 0200;
6841592Srgrimes	}
6851592Srgrimes	if (!UB) {
6861592Srgrimes		outbuf[obufcnt++] = c;
6871592Srgrimes		if (obufcnt >= OBUFSIZ)
6881592Srgrimes			oflush();
6891592Srgrimes	} else
6901592Srgrimes		write(STDOUT_FILENO, &c, 1);
6911592Srgrimes}
6921592Srgrimes
69315645Sjoergstatic void
6941592Srgrimesoflush()
6951592Srgrimes{
6961592Srgrimes	if (obufcnt)
6971592Srgrimes		write(STDOUT_FILENO, outbuf, obufcnt);
6981592Srgrimes	obufcnt = 0;
6991592Srgrimes}
7001592Srgrimes
70115645Sjoergstatic void
7021592Srgrimesprompt()
7031592Srgrimes{
7041592Srgrimes
7051592Srgrimes	putf(LM);
7061592Srgrimes	if (CO)
7071592Srgrimes		putchr('\n');
7081592Srgrimes}
7091592Srgrimes
71022208Sdavidn
71122208Sdavidnstatic char *
71222208Sdavidngetline(fd)
71322208Sdavidn	int fd;
71422208Sdavidn{
71522208Sdavidn	int i = 0;
71622208Sdavidn	static char linebuf[512];
71722208Sdavidn
71822208Sdavidn	/*
71922208Sdavidn	 * This is certainly slow, but it avoids having to include
72022208Sdavidn	 * stdio.h unnecessarily. Issue files should be small anyway.
72122208Sdavidn	 */
72222208Sdavidn	while (i < (sizeof linebuf - 3) && read(fd, linebuf+i, 1)==1) {
72322208Sdavidn		if (linebuf[i] == '\n') {
72422208Sdavidn			/* Don't rely on newline mode, assume raw */
72522208Sdavidn			linebuf[i++] = '\r';
72622208Sdavidn			linebuf[i++] = '\n';
72722208Sdavidn			linebuf[i] = '\0';
72822208Sdavidn			return linebuf;
72922208Sdavidn		}
73022208Sdavidn		++i;
73122208Sdavidn	}
73222208Sdavidn	linebuf[i] = '\0';
73322208Sdavidn	return i ? linebuf : 0;
73422208Sdavidn}
73522208Sdavidn
73615645Sjoergstatic void
7371592Srgrimesputf(cp)
73815645Sjoerg	register const char *cp;
7391592Srgrimes{
7401592Srgrimes	extern char editedhost[];
7411592Srgrimes	time_t t;
7421592Srgrimes	char *slash, db[100];
7431592Srgrimes
74422199Sdavidn	static struct utsname kerninfo;
74522199Sdavidn
74622199Sdavidn	if (!*kerninfo.sysname)
74722199Sdavidn		uname(&kerninfo);
74822199Sdavidn
7491592Srgrimes	while (*cp) {
7501592Srgrimes		if (*cp != '%') {
7511592Srgrimes			putchr(*cp++);
7521592Srgrimes			continue;
7531592Srgrimes		}
7541592Srgrimes		switch (*++cp) {
7551592Srgrimes
7561592Srgrimes		case 't':
75715645Sjoerg			slash = strrchr(ttyn, '/');
7581592Srgrimes			if (slash == (char *) 0)
7591592Srgrimes				puts(ttyn);
7601592Srgrimes			else
7611592Srgrimes				puts(&slash[1]);
7621592Srgrimes			break;
7631592Srgrimes
7641592Srgrimes		case 'h':
7651592Srgrimes			puts(editedhost);
7661592Srgrimes			break;
7671592Srgrimes
7681592Srgrimes		case 'd': {
76915645Sjoerg			t = (time_t)0;
7701592Srgrimes			(void)time(&t);
77115645Sjoerg			if (Lo)
77215645Sjoerg				(void)setlocale(LC_TIME, Lo);
77377874Syar			(void)strftime(db, sizeof(db), DF, localtime(&t));
7741592Srgrimes			puts(db);
7759875Sjkh			break;
77615645Sjoerg
77715645Sjoerg		case 's':
77815645Sjoerg			puts(kerninfo.sysname);
77915645Sjoerg			break;
78015645Sjoerg
78115645Sjoerg		case 'm':
78215645Sjoerg			puts(kerninfo.machine);
78315645Sjoerg			break;
78415645Sjoerg
78515645Sjoerg		case 'r':
78615645Sjoerg			puts(kerninfo.release);
78715645Sjoerg			break;
78815645Sjoerg
78915645Sjoerg		case 'v':
79015645Sjoerg			puts(kerninfo.version);
79115645Sjoerg			break;
7921592Srgrimes		}
7931592Srgrimes
7941592Srgrimes		case '%':
7951592Srgrimes			putchr('%');
7961592Srgrimes			break;
7971592Srgrimes		}
7981592Srgrimes		cp++;
7991592Srgrimes	}
8001592Srgrimes}
801