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.
13262435Sbrueffer * 3. Neither the name of the University nor the names of its contributors
141592Srgrimes *    may be used to endorse or promote products derived from this software
151592Srgrimes *    without specific prior written permission.
161592Srgrimes *
171592Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181592Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191592Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201592Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211592Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221592Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231592Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241592Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251592Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261592Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271592Srgrimes * SUCH DAMAGE.
281592Srgrimes */
291592Srgrimes
301592Srgrimes#ifndef lint
3131331Scharnierstatic const char copyright[] =
3215645Sjoerg"@(#) Copyright (c) 1980, 1993\n\
3315645Sjoerg	The Regents of the University of California.  All rights reserved.\n";
341592Srgrimes#endif /* not lint */
351592Srgrimes
361592Srgrimes#ifndef lint
3731331Scharnier#if 0
3831331Scharnierstatic char sccsid[] = "@(#)from: main.c	8.1 (Berkeley) 6/20/93";
3931331Scharnier#endif
401592Srgrimes#endif /* not lint */
41216582Scharnier#include <sys/cdefs.h>
42216582Scharnier__FBSDID("$FreeBSD$");
431592Srgrimes
441592Srgrimes#include <sys/param.h>
4515645Sjoerg#include <sys/ioctl.h>
4691216Sbde#include <sys/time.h>
4715645Sjoerg#include <sys/resource.h>
4891216Sbde#include <sys/stat.h>
4915645Sjoerg#include <sys/ttydefaults.h>
5015645Sjoerg#include <sys/utsname.h>
5166907Swollman
5231331Scharnier#include <ctype.h>
5315645Sjoerg#include <errno.h>
542286Sjkh#include <fcntl.h>
5531331Scharnier#include <locale.h>
5615645Sjoerg#include <libutil.h>
572286Sjkh#include <setjmp.h>
5815645Sjoerg#include <signal.h>
5915645Sjoerg#include <stdlib.h>
6015645Sjoerg#include <string.h>
612286Sjkh#include <syslog.h>
6215645Sjoerg#include <termios.h>
6315645Sjoerg#include <time.h>
642286Sjkh#include <unistd.h>
6515645Sjoerg
66144716Sstefanf#include "gettytab.h"
6791216Sbde#include "extern.h"
681592Srgrimes#include "pathnames.h"
691592Srgrimes
7015645Sjoerg/*
7115645Sjoerg * Set the amount of running time that getty should accumulate
7215645Sjoerg * before deciding that something is wrong and exit.
7315645Sjoerg */
7415645Sjoerg#define GETTY_TIMEOUT	60 /* seconds */
751592Srgrimes
7615645Sjoerg#undef CTRL
7715645Sjoerg#define CTRL(x)  (x&037)
7815645Sjoerg
7919697Spst/* defines for auto detection of incoming PPP calls (->PAP/CHAP) */
8019697Spst
8119697Spst#define PPP_FRAME           0x7e  /* PPP Framing character */
8219697Spst#define PPP_STATION         0xff  /* "All Station" character */
8319697Spst#define PPP_ESCAPE          0x7d  /* Escape Character */
8419697Spst#define PPP_CONTROL         0x03  /* PPP Control Field */
8519697Spst#define PPP_CONTROL_ESCAPED 0x23  /* PPP Control Field, escaped */
8619697Spst#define PPP_LCP_HI          0xc0  /* LCP protocol - high byte */
8719697Spst#define PPP_LCP_LOW         0x21  /* LCP protocol - low byte */
8819697Spst
89116533Syar/* original mode; flags've been reset using values from <sys/ttydefaults.h> */
90116533Syarstruct termios omode;
91116533Syar/* current mode */
92116533Syarstruct termios tmode;
9315645Sjoerg
941592Srgrimesint crmod, digit, lower, upper;
951592Srgrimes
961592Srgrimeschar	hostname[MAXHOSTNAMELEN];
9722400Sdavidnchar	name[MAXLOGNAME*3];
981592Srgrimeschar	dev[] = _PATH_DEV;
991592Srgrimeschar	ttyn[32];
1001592Srgrimes
1011592Srgrimes#define	OBUFSIZ		128
1021592Srgrimes#define	TABBUFSIZ	512
1031592Srgrimes
1041592Srgrimeschar	defent[TABBUFSIZ];
1051592Srgrimeschar	tabent[TABBUFSIZ];
106116533Syarconst	char *tname;
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
135117738Syarstatic void	defttymode(void);
13690301Simpstatic void	dingdong(int);
137116533Syarstatic void	dogettytab(void);
13890301Simpstatic int	getname(void);
13990301Simpstatic void	interrupt(int);
14090301Simpstatic void	oflush(void);
14190301Simpstatic void	prompt(void);
14290301Simpstatic void	putchr(int);
14390301Simpstatic void	putf(const char *);
14490301Simpstatic void	putpad(const char *);
14590301Simpstatic void	puts(const char *);
14690301Simpstatic void	timeoverrun(int);
14790301Simpstatic char	*getline(int);
148116164Syarstatic void	setttymode(int);
14990301Simpstatic int	opentty(const char *, int);
15015645Sjoerg
15122208Sdavidnjmp_buf timeout;
15222208Sdavidn
1531592Srgrimesstatic void
15490302Simpdingdong(int signo __unused)
1551592Srgrimes{
1561592Srgrimes	alarm(0);
1571592Srgrimes	longjmp(timeout, 1);
1581592Srgrimes}
1591592Srgrimes
1601592Srgrimesjmp_buf	intrupt;
1611592Srgrimes
1621592Srgrimesstatic void
16390302Simpinterrupt(int signo __unused)
1641592Srgrimes{
1651592Srgrimes	longjmp(intrupt, 1);
1661592Srgrimes}
1671592Srgrimes
16815645Sjoerg/*
16915645Sjoerg * Action to take when getty is running too long.
17015645Sjoerg */
17115645Sjoergstatic void
17290302Simptimeoverrun(int signo __unused)
17315645Sjoerg{
17415645Sjoerg
17531331Scharnier	syslog(LOG_ERR, "getty exiting due to excessive running time");
17615645Sjoerg	exit(1);
17715645Sjoerg}
17815645Sjoerg
17915645Sjoergint
18090301Simpmain(int argc, char *argv[])
1811592Srgrimes{
1822286Sjkh	extern	char **environ;
18322491Sdavidn	int first_sleep = 1, first_time = 1;
18415645Sjoerg	struct rlimit limit;
18519697Spst	int rval;
1861592Srgrimes
1871592Srgrimes	signal(SIGINT, SIG_IGN);
1882391Sache	signal(SIGQUIT, SIG_IGN);
1892286Sjkh
19015645Sjoerg	openlog("getty", LOG_ODELAY|LOG_CONS|LOG_PID, LOG_AUTH);
19145422Sbrian	gethostname(hostname, sizeof(hostname) - 1);
19245422Sbrian	hostname[sizeof(hostname) - 1] = '\0';
1931592Srgrimes	if (hostname[0] == '\0')
1941592Srgrimes		strcpy(hostname, "Amnesiac");
19515645Sjoerg
1961592Srgrimes	/*
19715645Sjoerg	 * Limit running time to deal with broken or dead lines.
19815645Sjoerg	 */
19915645Sjoerg	(void)signal(SIGXCPU, timeoverrun);
20015645Sjoerg	limit.rlim_max = RLIM_INFINITY;
20115645Sjoerg	limit.rlim_cur = GETTY_TIMEOUT;
20215645Sjoerg	(void)setrlimit(RLIMIT_CPU, &limit);
20315645Sjoerg
20422208Sdavidn	gettable("default", defent);
20522208Sdavidn	gendefaults();
20622208Sdavidn	tname = "default";
207116329Sgreen	if (argc > 1)
20822208Sdavidn		tname = argv[1];
20922208Sdavidn
21015645Sjoerg	/*
2111592Srgrimes	 * The following is a work around for vhangup interactions
2121592Srgrimes	 * which cause great problems getting window systems started.
2131592Srgrimes	 * If the tty line is "-", we do the old style getty presuming
2148870Srgrimes	 * that the file descriptors are already set up for us.
2151592Srgrimes	 * J. Gettys - MIT Project Athena.
2161592Srgrimes	 */
217116533Syar	if (argc <= 2 || strcmp(argv[2], "-") == 0)
21822208Sdavidn	    strcpy(ttyn, ttyname(STDIN_FILENO));
219116533Syar	else {
2201592Srgrimes	    strcpy(ttyn, dev);
2211592Srgrimes	    strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
2221592Srgrimes	    if (strcmp(argv[0], "+") != 0) {
2231592Srgrimes		chown(ttyn, 0, 0);
2241592Srgrimes		chmod(ttyn, 0600);
2251592Srgrimes		revoke(ttyn);
22622208Sdavidn
227116533Syar		/*
228116533Syar		 * Do the first scan through gettytab.
229116533Syar		 * Terminal mode parameters will be wrong until
230116533Syar		 * defttymode() called, but they're irrelevant for
231116533Syar		 * the initial setup of the terminal device.
23222208Sdavidn		 */
233116533Syar		dogettytab();
234116533Syar
235116533Syar		/*
236116533Syar		 * Init or answer modem sequence has been specified.
237116533Syar		 */
238116533Syar		if (IC || AC) {
23922208Sdavidn			if (!opentty(ttyn, O_RDWR|O_NONBLOCK))
24022208Sdavidn				exit(1);
241116533Syar			defttymode();
242116533Syar			setttymode(1);
243116533Syar		}
244116533Syar
245116533Syar		if (IC) {
24622208Sdavidn			if (getty_chat(IC, CT, DC) > 0) {
24722208Sdavidn				syslog(LOG_ERR, "modem init problem on %s", ttyn);
24822491Sdavidn				(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
24922208Sdavidn				exit(1);
2501592Srgrimes			}
2511592Srgrimes		}
25222208Sdavidn
25322208Sdavidn		if (AC) {
25422208Sdavidn			int i, rfds;
25590302Simp			struct timeval to;
25622208Sdavidn
25722208Sdavidn        		rfds = 1 << 0;	/* FD_SET */
25890302Simp        		to.tv_sec = RT;
25990302Simp        		to.tv_usec = 0;
26022208Sdavidn        		i = select(32, (fd_set*)&rfds, (fd_set*)NULL,
26190302Simp        			       (fd_set*)NULL, RT ? &to : NULL);
26222208Sdavidn        		if (i < 0) {
26322208Sdavidn				syslog(LOG_ERR, "select %s: %m", ttyn);
26422208Sdavidn			} else if (i == 0) {
26522208Sdavidn				syslog(LOG_NOTICE, "recycle tty %s", ttyn);
26622491Sdavidn				(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
26722208Sdavidn				exit(0);  /* recycle for init */
26822208Sdavidn			}
26922208Sdavidn			i = getty_chat(AC, CT, DC);
27022208Sdavidn			if (i > 0) {
27122208Sdavidn				syslog(LOG_ERR, "modem answer problem on %s", ttyn);
27222491Sdavidn				(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
27322208Sdavidn				exit(1);
27422208Sdavidn			}
27564076Snsayer		} else { /* maybe blocking open */
27664076Snsayer			if (!opentty(ttyn, O_RDWR | (NC ? O_NONBLOCK : 0 )))
27722208Sdavidn				exit(1);
27822208Sdavidn		}
2791592Srgrimes	    }
2801592Srgrimes	}
2811592Srgrimes
282116533Syar	defttymode();
2831592Srgrimes	for (;;) {
2841592Srgrimes
28522491Sdavidn		/*
28622491Sdavidn		 * if a delay was specified then sleep for that
28722491Sdavidn		 * number of seconds before writing the initial prompt
28822491Sdavidn		 */
28922491Sdavidn		if (first_sleep && DE) {
29022491Sdavidn		    sleep(DE);
29122491Sdavidn		    /* remove any noise */
29222491Sdavidn		    (void)tcflush(STDIN_FILENO, TCIOFLUSH);
29322491Sdavidn		}
29422491Sdavidn		first_sleep = 0;
29522491Sdavidn
296116164Syar		setttymode(0);
2971592Srgrimes		if (AB) {
2981592Srgrimes			tname = autobaud();
299116533Syar			dogettytab();
3001592Srgrimes			continue;
3011592Srgrimes		}
3021592Srgrimes		if (PS) {
3031592Srgrimes			tname = portselector();
304116533Syar			dogettytab();
3051592Srgrimes			continue;
3061592Srgrimes		}
3071592Srgrimes		if (CL && *CL)
3081592Srgrimes			putpad(CL);
3091592Srgrimes		edithost(HE);
31021120Smsmith
31122208Sdavidn		/* if this is the first time through this, and an
31222208Sdavidn		   issue file has been given, then send it */
31322208Sdavidn		if (first_time && IF) {
31422208Sdavidn			int fd;
31522208Sdavidn
31622208Sdavidn			if ((fd = open(IF, O_RDONLY)) != -1) {
31722208Sdavidn				char * cp;
31822208Sdavidn
31922208Sdavidn				while ((cp = getline(fd)) != NULL) {
32022208Sdavidn					  putf(cp);
32122208Sdavidn				}
32222208Sdavidn				close(fd);
32322208Sdavidn			}
32422208Sdavidn		}
32522491Sdavidn		first_time = 0;
32622208Sdavidn
327109555Ssobomax		if (IM && *IM && !(PL && PP))
3281592Srgrimes			putf(IM);
3291592Srgrimes		if (setjmp(timeout)) {
33015659Sache			cfsetispeed(&tmode, B0);
33115659Sache			cfsetospeed(&tmode, B0);
33222208Sdavidn			(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
3331592Srgrimes			exit(1);
3341592Srgrimes		}
3351592Srgrimes		if (TO) {
3361592Srgrimes			signal(SIGALRM, dingdong);
3371592Srgrimes			alarm(TO);
3381592Srgrimes		}
339115900Syar
340115900Syar		rval = 0;
34145291Speter		if (AL) {
34245291Speter			const char *p = AL;
34345291Speter			char *q = name;
34445291Speter
34545291Speter			while (*p && q < &name[sizeof name - 1]) {
34645291Speter				if (isupper(*p))
34745291Speter					upper = 1;
34845291Speter				else if (islower(*p))
34945291Speter					lower = 1;
35045291Speter				else if (isdigit(*p))
351116154Syar					digit = 1;
35245291Speter				*q++ = *p++;
35345291Speter			}
354109540Ssobomax		} else if (!(PL && PP))
35545291Speter			rval = getname();
356109540Ssobomax		if (rval == 2 || (PL && PP)) {
35726415Sdavidn			oflush();
35826415Sdavidn			alarm(0);
35944615Sbrian			limit.rlim_max = RLIM_INFINITY;
36044615Sbrian			limit.rlim_cur = RLIM_INFINITY;
36144615Sbrian			(void)setrlimit(RLIMIT_CPU, &limit);
36219697Spst			execle(PP, "ppplogin", ttyn, (char *) 0, env);
36319697Spst			syslog(LOG_ERR, "%s: %m", PP);
36419697Spst			exit(1);
36545291Speter		} else if (rval || AL) {
36690301Simp			int i;
3671592Srgrimes
36815645Sjoerg			oflush();
3691592Srgrimes			alarm(0);
3701592Srgrimes			signal(SIGALRM, SIG_DFL);
371115900Syar			if (name[0] == '\0')
372115900Syar				continue;
3731592Srgrimes			if (name[0] == '-') {
3741592Srgrimes				puts("user names may not start with '-'.");
3751592Srgrimes				continue;
3761592Srgrimes			}
377115900Syar			if (!(upper || lower || digit)) {
378115900Syar				if (AL) {
379115900Syar					syslog(LOG_ERR,
380115900Syar					    "invalid auto-login name: %s", AL);
381115900Syar					exit(1);
382115900Syar				} else
383115900Syar					continue;
384115900Syar			}
38556725Sbde			set_flags(2);
38615645Sjoerg			if (crmod) {
38715645Sjoerg				tmode.c_iflag |= ICRNL;
38815645Sjoerg				tmode.c_oflag |= ONLCR;
38915645Sjoerg			}
39015645Sjoerg#if REALLY_OLD_TTYS
39115645Sjoerg			if (upper || UC)
39215645Sjoerg				tmode.sg_flags |= LCASE;
39315645Sjoerg			if (lower || LC)
39415645Sjoerg				tmode.sg_flags &= ~LCASE;
39515645Sjoerg#endif
39622208Sdavidn			if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
39722208Sdavidn				syslog(LOG_ERR, "tcsetattr %s: %m", ttyn);
39815645Sjoerg				exit(1);
39915645Sjoerg			}
40015645Sjoerg			signal(SIGINT, SIG_DFL);
4011592Srgrimes			for (i = 0; environ[i] != (char *)0; i++)
4021592Srgrimes				env[i] = environ[i];
4031592Srgrimes			makeenv(&env[i]);
4041592Srgrimes
40515645Sjoerg			limit.rlim_max = RLIM_INFINITY;
40615645Sjoerg			limit.rlim_cur = RLIM_INFINITY;
40715645Sjoerg			(void)setrlimit(RLIMIT_CPU, &limit);
40845291Speter			execle(LO, "login", AL ? "-fp" : "-p", name,
40945291Speter			    (char *) 0, env);
4101592Srgrimes			syslog(LOG_ERR, "%s: %m", LO);
4111592Srgrimes			exit(1);
4121592Srgrimes		}
4131592Srgrimes		alarm(0);
4141592Srgrimes		signal(SIGALRM, SIG_DFL);
41515645Sjoerg		signal(SIGINT, SIG_IGN);
416116164Syar		if (NX && *NX) {
4171592Srgrimes			tname = NX;
418116533Syar			dogettytab();
419116164Syar		}
4201592Srgrimes	}
4211592Srgrimes}
4221592Srgrimes
42315645Sjoergstatic int
42490302Simpopentty(const char *tty, int flags)
42522208Sdavidn{
426135941Simp	int i;
42722208Sdavidn	int failopenlogged = 0;
42822208Sdavidn
429135941Simp	while ((i = open(tty, flags)) == -1)
43022208Sdavidn	{
431135941Simp		if (!failopenlogged) {
43290302Simp			syslog(LOG_ERR, "open %s: %m", tty);
43322208Sdavidn			failopenlogged = 1;
43422208Sdavidn		}
43522208Sdavidn		sleep(60);
43622208Sdavidn	}
437135941Simp	if (login_tty(i) < 0) {
438135941Simp		if (daemon(0,0) < 0) {
439135941Simp			syslog(LOG_ERR,"daemon: %m");
440135941Simp			close(i);
441135941Simp			return 0;
44268888Sjwd		}
443135941Simp		if (login_tty(i) < 0) {
444135941Simp			syslog(LOG_ERR, "login_tty %s: %m", tty);
445135941Simp			close(i);
446135941Simp			return 0;
447135941Simp		}
44822208Sdavidn	}
449135941Simp	return 1;
45022208Sdavidn}
45122208Sdavidn
45222208Sdavidnstatic void
453214680Seddefttymode(void)
45422208Sdavidn{
455214680Sed	struct termios def;
456116533Syar
457116533Syar	/* Start with default tty settings. */
45822208Sdavidn	if (tcgetattr(STDIN_FILENO, &tmode) < 0) {
45922208Sdavidn		syslog(LOG_ERR, "tcgetattr %s: %m", ttyn);
46022208Sdavidn		exit(1);
46122208Sdavidn	}
462116533Syar	omode = tmode; /* fill c_cc for dogettytab() */
463116533Syar	dogettytab();
464116533Syar	/*
465116533Syar	 * Don't rely on the driver too much, and initialize crucial
466116533Syar	 * things according to <sys/ttydefaults.h>.  Avoid clobbering
467116533Syar	 * the c_cc[] settings however, the console drivers might wish
468116533Syar	 * to leave their idea of the preferred VERASE key value
469116533Syar	 * there.
470116533Syar	 */
471214680Sed	cfmakesane(&def);
472214680Sed	tmode.c_iflag = def.c_iflag;
473214680Sed	tmode.c_oflag = def.c_oflag;
474214680Sed	tmode.c_lflag = def.c_lflag;
475214680Sed	tmode.c_cflag = def.c_cflag;
476116533Syar	if (NC)
477116533Syar		tmode.c_cflag |= CLOCAL;
478116533Syar	omode = tmode;
47922208Sdavidn}
48022208Sdavidn
48122208Sdavidnstatic void
482116164Syarsetttymode(int raw)
48322208Sdavidn{
48422208Sdavidn	int off = 0;
48522208Sdavidn
48622208Sdavidn	(void)tcflush(STDIN_FILENO, TCIOFLUSH);	/* clear out the crap */
48722208Sdavidn	ioctl(STDIN_FILENO, FIONBIO, &off);	/* turn off non-blocking mode */
48822208Sdavidn	ioctl(STDIN_FILENO, FIOASYNC, &off);	/* ditto for async mode */
48922208Sdavidn
49022208Sdavidn	if (IS)
49122208Sdavidn		cfsetispeed(&tmode, speed(IS));
49222208Sdavidn	else if (SP)
49322208Sdavidn		cfsetispeed(&tmode, speed(SP));
49422208Sdavidn	if (OS)
49522208Sdavidn		cfsetospeed(&tmode, speed(OS));
49622208Sdavidn	else if (SP)
49722208Sdavidn		cfsetospeed(&tmode, speed(SP));
49856725Sbde	set_flags(0);
49922208Sdavidn	setchars();
50022208Sdavidn	if (raw)
50122208Sdavidn		cfmakeraw(&tmode);
50222208Sdavidn	if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
50322208Sdavidn		syslog(LOG_ERR, "tcsetattr %s: %m", ttyn);
50422208Sdavidn		exit(1);
50522208Sdavidn	}
50622208Sdavidn}
50722208Sdavidn
50822208Sdavidn
50922208Sdavidnstatic int
51090301Simpgetname(void)
5111592Srgrimes{
51290301Simp	int c;
51390301Simp	char *np;
51419697Spst	unsigned char cs;
51522208Sdavidn	int ppp_state = 0;
51619697Spst	int ppp_connection = 0;
5171592Srgrimes
5181592Srgrimes	/*
5191592Srgrimes	 * Interrupt may happen if we use CBREAK mode
5201592Srgrimes	 */
5211592Srgrimes	if (setjmp(intrupt)) {
5221592Srgrimes		signal(SIGINT, SIG_IGN);
5231592Srgrimes		return (0);
5241592Srgrimes	}
5251592Srgrimes	signal(SIGINT, interrupt);
52656725Sbde	set_flags(1);
5271592Srgrimes	prompt();
5282286Sjkh	oflush();
5291592Srgrimes	if (PF > 0) {
5301592Srgrimes		sleep(PF);
5311592Srgrimes		PF = 0;
5321592Srgrimes	}
53322208Sdavidn	if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
53415645Sjoerg		syslog(LOG_ERR, "%s: %m", ttyn);
53515645Sjoerg		exit(1);
53615645Sjoerg	}
5371592Srgrimes	crmod = digit = lower = upper = 0;
5381592Srgrimes	np = name;
5391592Srgrimes	for (;;) {
5401592Srgrimes		oflush();
5411592Srgrimes		if (read(STDIN_FILENO, &cs, 1) <= 0)
5421592Srgrimes			exit(0);
5431592Srgrimes		if ((c = cs&0177) == 0)
5441592Srgrimes			return (0);
54519697Spst
54619697Spst		/* PPP detection state machine..
54719697Spst		   Look for sequences:
54819697Spst		   PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or
54919697Spst		   PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC)
55019697Spst		   See RFC1662.
55119697Spst		   Derived from code from Michael Hancock, <michaelh@cet.co.jp>
55219697Spst		   and Erik 'PPP' Olson, <eriko@wrq.com>
55319697Spst		 */
55419697Spst
55519697Spst		if (PP && (cs == PPP_FRAME)) {
55619697Spst			ppp_state = 1;
55719697Spst		} else if (ppp_state == 1 && cs == PPP_STATION) {
55819697Spst			ppp_state = 2;
55919697Spst		} else if (ppp_state == 2 && cs == PPP_ESCAPE) {
56019697Spst			ppp_state = 3;
56119697Spst		} else if ((ppp_state == 2 && cs == PPP_CONTROL)
56219697Spst			|| (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) {
56319697Spst			ppp_state = 4;
56419697Spst		} else if (ppp_state == 4 && cs == PPP_LCP_HI) {
56519697Spst			ppp_state = 5;
56619697Spst		} else if (ppp_state == 5 && cs == PPP_LCP_LOW) {
56719697Spst			ppp_connection = 1;
56819697Spst			break;
56919697Spst		} else {
57019697Spst			ppp_state = 0;
57119697Spst		}
57219697Spst
57315645Sjoerg		if (c == EOT || c == CTRL('d'))
574115900Syar			exit(0);
57522211Sdavidn		if (c == '\r' || c == '\n' || np >= &name[sizeof name-1]) {
5761592Srgrimes			putf("\r\n");
5771592Srgrimes			break;
5781592Srgrimes		}
5791592Srgrimes		if (islower(c))
5801592Srgrimes			lower = 1;
5811592Srgrimes		else if (isupper(c))
5821592Srgrimes			upper = 1;
5832286Sjkh		else if (c == ERASE || c == '\b' || c == 0177) {
5841592Srgrimes			if (np > name) {
5851592Srgrimes				np--;
58615645Sjoerg				if (cfgetospeed(&tmode) >= 1200)
5871592Srgrimes					puts("\b \b");
5881592Srgrimes				else
5891592Srgrimes					putchr(cs);
5901592Srgrimes			}
5911592Srgrimes			continue;
59215645Sjoerg		} else if (c == KILL || c == CTRL('u')) {
5931592Srgrimes			putchr('\r');
59415645Sjoerg			if (cfgetospeed(&tmode) < 1200)
5951592Srgrimes				putchr('\n');
5961592Srgrimes			/* this is the way they do it down under ... */
5971592Srgrimes			else if (np > name)
5981592Srgrimes				puts("                                     \r");
5991592Srgrimes			prompt();
600115900Syar			digit = lower = upper = 0;
6011592Srgrimes			np = name;
6021592Srgrimes			continue;
6031592Srgrimes		} else if (isdigit(c))
604116154Syar			digit = 1;
6051592Srgrimes		if (IG && (c <= ' ' || c > 0176))
6061592Srgrimes			continue;
6071592Srgrimes		*np++ = c;
6081592Srgrimes		putchr(cs);
6091592Srgrimes	}
6101592Srgrimes	signal(SIGINT, SIG_IGN);
6111592Srgrimes	*np = 0;
6121592Srgrimes	if (c == '\r')
6131592Srgrimes		crmod = 1;
61415645Sjoerg	if ((upper && !lower && !LC) || UC)
6151592Srgrimes		for (np = name; *np; np++)
6161592Srgrimes			if (isupper(*np))
6171592Srgrimes				*np = tolower(*np);
61819697Spst	return (1 + ppp_connection);
6191592Srgrimes}
6201592Srgrimes
62115645Sjoergstatic void
62290301Simpputpad(const char *s)
6231592Srgrimes{
62490301Simp	int pad = 0;
62515645Sjoerg	speed_t ospeed = cfgetospeed(&tmode);
6261592Srgrimes
6271592Srgrimes	if (isdigit(*s)) {
6281592Srgrimes		while (isdigit(*s)) {
6291592Srgrimes			pad *= 10;
6301592Srgrimes			pad += *s++ - '0';
6311592Srgrimes		}
6321592Srgrimes		pad *= 10;
6331592Srgrimes		if (*s == '.' && isdigit(s[1])) {
6341592Srgrimes			pad += s[1] - '0';
6351592Srgrimes			s += 2;
6361592Srgrimes		}
6371592Srgrimes	}
6381592Srgrimes
6391592Srgrimes	puts(s);
6401592Srgrimes	/*
6411592Srgrimes	 * If no delay needed, or output speed is
6421592Srgrimes	 * not comprehensible, then don't try to delay.
6431592Srgrimes	 */
64415645Sjoerg	if (pad == 0 || ospeed <= 0)
6451592Srgrimes		return;
6461592Srgrimes
6471592Srgrimes	/*
6481592Srgrimes	 * Round up by a half a character frame, and then do the delay.
6491592Srgrimes	 * Too bad there are no user program accessible programmed delays.
6501592Srgrimes	 * Transmitting pad characters slows many terminals down and also
6511592Srgrimes	 * loads the system.
6521592Srgrimes	 */
65315645Sjoerg	pad = (pad * ospeed + 50000) / 100000;
65415645Sjoerg	while (pad--)
6551592Srgrimes		putchr(*PC);
6561592Srgrimes}
6571592Srgrimes
65815645Sjoergstatic void
65990301Simpputs(const char *s)
6601592Srgrimes{
6611592Srgrimes	while (*s)
6621592Srgrimes		putchr(*s++);
6631592Srgrimes}
6641592Srgrimes
6651592Srgrimeschar	outbuf[OBUFSIZ];
6661592Srgrimesint	obufcnt = 0;
6671592Srgrimes
66815645Sjoergstatic void
66990301Simpputchr(int cc)
6701592Srgrimes{
6711592Srgrimes	char c;
6721592Srgrimes
6731592Srgrimes	c = cc;
6741592Srgrimes	if (!NP) {
6751592Srgrimes		c |= partab[c&0177] & 0200;
6761592Srgrimes		if (OP)
6771592Srgrimes			c ^= 0200;
6781592Srgrimes	}
6791592Srgrimes	if (!UB) {
6801592Srgrimes		outbuf[obufcnt++] = c;
6811592Srgrimes		if (obufcnt >= OBUFSIZ)
6821592Srgrimes			oflush();
6831592Srgrimes	} else
6841592Srgrimes		write(STDOUT_FILENO, &c, 1);
6851592Srgrimes}
6861592Srgrimes
68715645Sjoergstatic void
68890301Simpoflush(void)
6891592Srgrimes{
6901592Srgrimes	if (obufcnt)
6911592Srgrimes		write(STDOUT_FILENO, outbuf, obufcnt);
6921592Srgrimes	obufcnt = 0;
6931592Srgrimes}
6941592Srgrimes
69515645Sjoergstatic void
69690301Simpprompt(void)
6971592Srgrimes{
6981592Srgrimes
6991592Srgrimes	putf(LM);
7001592Srgrimes	if (CO)
7011592Srgrimes		putchr('\n');
7021592Srgrimes}
7031592Srgrimes
70422208Sdavidn
70522208Sdavidnstatic char *
70690301Simpgetline(int fd)
70722208Sdavidn{
70822208Sdavidn	int i = 0;
70922208Sdavidn	static char linebuf[512];
71022208Sdavidn
71122208Sdavidn	/*
71222208Sdavidn	 * This is certainly slow, but it avoids having to include
71322208Sdavidn	 * stdio.h unnecessarily. Issue files should be small anyway.
71422208Sdavidn	 */
71522208Sdavidn	while (i < (sizeof linebuf - 3) && read(fd, linebuf+i, 1)==1) {
71622208Sdavidn		if (linebuf[i] == '\n') {
71722208Sdavidn			/* Don't rely on newline mode, assume raw */
71822208Sdavidn			linebuf[i++] = '\r';
71922208Sdavidn			linebuf[i++] = '\n';
72022208Sdavidn			linebuf[i] = '\0';
72122208Sdavidn			return linebuf;
72222208Sdavidn		}
72322208Sdavidn		++i;
72422208Sdavidn	}
72522208Sdavidn	linebuf[i] = '\0';
72622208Sdavidn	return i ? linebuf : 0;
72722208Sdavidn}
72822208Sdavidn
72915645Sjoergstatic void
73090301Simpputf(const char *cp)
7311592Srgrimes{
7321592Srgrimes	extern char editedhost[];
7331592Srgrimes	time_t t;
7341592Srgrimes	char *slash, db[100];
7351592Srgrimes
73622199Sdavidn	static struct utsname kerninfo;
73722199Sdavidn
73822199Sdavidn	if (!*kerninfo.sysname)
73922199Sdavidn		uname(&kerninfo);
74022199Sdavidn
7411592Srgrimes	while (*cp) {
7421592Srgrimes		if (*cp != '%') {
7431592Srgrimes			putchr(*cp++);
7441592Srgrimes			continue;
7451592Srgrimes		}
7461592Srgrimes		switch (*++cp) {
7471592Srgrimes
7481592Srgrimes		case 't':
74915645Sjoerg			slash = strrchr(ttyn, '/');
7501592Srgrimes			if (slash == (char *) 0)
7511592Srgrimes				puts(ttyn);
7521592Srgrimes			else
7531592Srgrimes				puts(&slash[1]);
7541592Srgrimes			break;
7551592Srgrimes
7561592Srgrimes		case 'h':
7571592Srgrimes			puts(editedhost);
7581592Srgrimes			break;
7591592Srgrimes
7601592Srgrimes		case 'd': {
76115645Sjoerg			t = (time_t)0;
7621592Srgrimes			(void)time(&t);
76315645Sjoerg			if (Lo)
76415645Sjoerg				(void)setlocale(LC_TIME, Lo);
76577874Syar			(void)strftime(db, sizeof(db), DF, localtime(&t));
7661592Srgrimes			puts(db);
7679875Sjkh			break;
76815645Sjoerg
76915645Sjoerg		case 's':
77015645Sjoerg			puts(kerninfo.sysname);
77115645Sjoerg			break;
77215645Sjoerg
77315645Sjoerg		case 'm':
77415645Sjoerg			puts(kerninfo.machine);
77515645Sjoerg			break;
77615645Sjoerg
77715645Sjoerg		case 'r':
77815645Sjoerg			puts(kerninfo.release);
77915645Sjoerg			break;
78015645Sjoerg
78115645Sjoerg		case 'v':
78215645Sjoerg			puts(kerninfo.version);
78315645Sjoerg			break;
7841592Srgrimes		}
7851592Srgrimes
7861592Srgrimes		case '%':
7871592Srgrimes			putchr('%');
7881592Srgrimes			break;
7891592Srgrimes		}
7901592Srgrimes		cp++;
7911592Srgrimes	}
7921592Srgrimes}
793116164Syar
794116164Syar/*
795116164Syar * Read a gettytab database entry and perform necessary quirks.
796116164Syar */
797116164Syarstatic void
798216582Scharnierdogettytab(void)
799116164Syar{
800116164Syar
801116533Syar	/* Read the database entry. */
802116164Syar	gettable(tname, tabent);
803116164Syar
804116164Syar	/*
805116164Syar	 * Avoid inheriting the parity values from the default entry
806116164Syar	 * if any of them is set in the current entry.
807116164Syar	 * Mixing different parity settings is unreasonable.
808116164Syar	 */
809116164Syar	if (OPset || EPset || APset || NPset)
810116164Syar		OPset = EPset = APset = NPset = 1;
811116164Syar
812116533Syar	/* Fill in default values for unset capabilities. */
813116164Syar	setdefaults();
814116164Syar}
815