main.c revision 22491
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
3515645Sjoergstatic 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
4115645Sjoerg/*static char sccsid[] = "from: @(#)main.c	8.1 (Berkeley) 6/20/93";*/
4221673Sjkhstatic char rcsid[] = "$FreeBSD: head/libexec/getty/main.c 22491 1997-02-09 16:12:08Z davidn $";
431592Srgrimes#endif /* not lint */
441592Srgrimes
451592Srgrimes#include <sys/param.h>
461592Srgrimes#include <sys/stat.h>
4715645Sjoerg#include <sys/ioctl.h>
4815645Sjoerg#include <sys/resource.h>
4915645Sjoerg#include <sys/ttydefaults.h>
5015645Sjoerg#include <sys/utsname.h>
5115645Sjoerg#include <errno.h>
522286Sjkh#include <signal.h>
532286Sjkh#include <fcntl.h>
542286Sjkh#include <time.h>
551592Srgrimes#include <ctype.h>
5615645Sjoerg#include <fcntl.h>
5715645Sjoerg#include <libutil.h>
5815645Sjoerg#include <locale.h>
592286Sjkh#include <setjmp.h>
6015645Sjoerg#include <signal.h>
6115645Sjoerg#include <stdlib.h>
6215645Sjoerg#include <string.h>
632286Sjkh#include <syslog.h>
6415645Sjoerg#include <termios.h>
6515645Sjoerg#include <time.h>
662286Sjkh#include <unistd.h>
6715645Sjoerg
681592Srgrimes#include "gettytab.h"
691592Srgrimes#include "pathnames.h"
7015645Sjoerg#include "extern.h"
711592Srgrimes
7215645Sjoerg/*
7315645Sjoerg * Set the amount of running time that getty should accumulate
7415645Sjoerg * before deciding that something is wrong and exit.
7515645Sjoerg */
7615645Sjoerg#define GETTY_TIMEOUT	60 /* seconds */
771592Srgrimes
7815645Sjoerg#undef CTRL
7915645Sjoerg#define CTRL(x)  (x&037)
8015645Sjoerg
8119697Spst/* defines for auto detection of incoming PPP calls (->PAP/CHAP) */
8219697Spst
8319697Spst#define PPP_FRAME           0x7e  /* PPP Framing character */
8419697Spst#define PPP_STATION         0xff  /* "All Station" character */
8519697Spst#define PPP_ESCAPE          0x7d  /* Escape Character */
8619697Spst#define PPP_CONTROL         0x03  /* PPP Control Field */
8719697Spst#define PPP_CONTROL_ESCAPED 0x23  /* PPP Control Field, escaped */
8819697Spst#define PPP_LCP_HI          0xc0  /* LCP protocol - high byte */
8919697Spst#define PPP_LCP_LOW         0x21  /* LCP protocol - low byte */
9019697Spst
9115645Sjoergstruct termios tmode, omode;
9215645Sjoerg
931592Srgrimesint crmod, digit, lower, upper;
941592Srgrimes
951592Srgrimeschar	hostname[MAXHOSTNAMELEN];
9622400Sdavidnchar	name[MAXLOGNAME*3];
971592Srgrimeschar	dev[] = _PATH_DEV;
981592Srgrimeschar	ttyn[32];
991592Srgrimes
1001592Srgrimes#define	OBUFSIZ		128
1011592Srgrimes#define	TABBUFSIZ	512
1021592Srgrimes
1031592Srgrimeschar	defent[TABBUFSIZ];
1041592Srgrimeschar	tabent[TABBUFSIZ];
1051592Srgrimes
1061592Srgrimeschar	*env[128];
1071592Srgrimes
1081592Srgrimeschar partab[] = {
1091592Srgrimes	0001,0201,0201,0001,0201,0001,0001,0201,
1101592Srgrimes	0202,0004,0003,0205,0005,0206,0201,0001,
1111592Srgrimes	0201,0001,0001,0201,0001,0201,0201,0001,
1121592Srgrimes	0001,0201,0201,0001,0201,0001,0001,0201,
1131592Srgrimes	0200,0000,0000,0200,0000,0200,0200,0000,
1141592Srgrimes	0000,0200,0200,0000,0200,0000,0000,0200,
1151592Srgrimes	0000,0200,0200,0000,0200,0000,0000,0200,
1161592Srgrimes	0200,0000,0000,0200,0000,0200,0200,0000,
1171592Srgrimes	0200,0000,0000,0200,0000,0200,0200,0000,
1181592Srgrimes	0000,0200,0200,0000,0200,0000,0000,0200,
1191592Srgrimes	0000,0200,0200,0000,0200,0000,0000,0200,
1201592Srgrimes	0200,0000,0000,0200,0000,0200,0200,0000,
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,0201
1251592Srgrimes};
1261592Srgrimes
12715645Sjoerg#define	ERASE	tmode.c_cc[VERASE]
12815645Sjoerg#define	KILL	tmode.c_cc[VKILL]
12915645Sjoerg#define	EOT	tmode.c_cc[VEOF]
1301592Srgrimes
13115645Sjoergstatic void	dingdong __P((int));
13215645Sjoergstatic int	getname __P((void));
13315645Sjoergstatic void	interrupt __P((int));
13415645Sjoergstatic void	oflush __P((void));
13515645Sjoergstatic void	prompt __P((void));
13615645Sjoergstatic void	putchr __P((int));
13715645Sjoergstatic void	putf __P((const char *));
13815645Sjoergstatic void	putpad __P((const char *));
13915645Sjoergstatic void	puts __P((const char *));
14015645Sjoergstatic void	timeoverrun __P((int));
14122208Sdavidnstatic char	*getline __P((int));
14222208Sdavidnstatic void	setttymode __P((const char *, int));
14322208Sdavidnstatic void	setdefttymode __P((const char *));
14422208Sdavidnstatic int	opentty __P((const char *, int));
14515645Sjoerg
14615645Sjoergint		main __P((int, char **));
14715645Sjoerg
14822208Sdavidnjmp_buf timeout;
14922208Sdavidn
1501592Srgrimesstatic void
15115645Sjoergdingdong(signo)
15215645Sjoerg	int signo;
1531592Srgrimes{
1541592Srgrimes	alarm(0);
1551592Srgrimes	longjmp(timeout, 1);
1561592Srgrimes}
1571592Srgrimes
1581592Srgrimesjmp_buf	intrupt;
1591592Srgrimes
1601592Srgrimesstatic void
16115645Sjoerginterrupt(signo)
16215645Sjoerg	int signo;
1631592Srgrimes{
1641592Srgrimes	longjmp(intrupt, 1);
1651592Srgrimes}
1661592Srgrimes
16715645Sjoerg/*
16815645Sjoerg * Action to take when getty is running too long.
16915645Sjoerg */
17015645Sjoergstatic void
17115645Sjoergtimeoverrun(signo)
17215645Sjoerg	int signo;
17315645Sjoerg{
17415645Sjoerg
17515645Sjoerg	syslog(LOG_ERR, "getty exiting due to excessive running time\n");
17615645Sjoerg	exit(1);
17715645Sjoerg}
17815645Sjoerg
17915645Sjoergint
1801592Srgrimesmain(argc, argv)
1811592Srgrimes	int argc;
1822286Sjkh	char **argv;
1831592Srgrimes{
1842286Sjkh	extern	char **environ;
18515645Sjoerg	const char *tname;
18622491Sdavidn	int repcnt = 0, failopenlogged = 0;
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);
1951592Srgrimes	gethostname(hostname, sizeof(hostname));
1961592Srgrimes	if (hostname[0] == '\0')
1971592Srgrimes		strcpy(hostname, "Amnesiac");
19815645Sjoerg
1991592Srgrimes	/*
20015645Sjoerg	 * Limit running time to deal with broken or dead lines.
20115645Sjoerg	 */
20215645Sjoerg	(void)signal(SIGXCPU, timeoverrun);
20315645Sjoerg	limit.rlim_max = RLIM_INFINITY;
20415645Sjoerg	limit.rlim_cur = GETTY_TIMEOUT;
20515645Sjoerg	(void)setrlimit(RLIMIT_CPU, &limit);
20615645Sjoerg
20722208Sdavidn	gettable("default", defent);
20822208Sdavidn	gendefaults();
20922208Sdavidn	tname = "default";
21022208Sdavidn	if (argc > 1)
21122208Sdavidn		tname = argv[1];
21222208Sdavidn
21315645Sjoerg	/*
2141592Srgrimes	 * The following is a work around for vhangup interactions
2151592Srgrimes	 * which cause great problems getting window systems started.
2161592Srgrimes	 * If the tty line is "-", we do the old style getty presuming
2178870Srgrimes	 * that the file descriptors are already set up for us.
2181592Srgrimes	 * J. Gettys - MIT Project Athena.
2191592Srgrimes	 */
2201592Srgrimes	if (argc <= 2 || strcmp(argv[2], "-") == 0)
22122208Sdavidn	    strcpy(ttyn, ttyname(STDIN_FILENO));
2221592Srgrimes	else {
2231592Srgrimes	    int i;
2241592Srgrimes
2251592Srgrimes	    strcpy(ttyn, dev);
2261592Srgrimes	    strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
2271592Srgrimes	    if (strcmp(argv[0], "+") != 0) {
2281592Srgrimes		chown(ttyn, 0, 0);
2291592Srgrimes		chmod(ttyn, 0600);
2301592Srgrimes		revoke(ttyn);
23122208Sdavidn
23222208Sdavidn		gettable(tname, tabent);
23322208Sdavidn
23422208Sdavidn		/* Init modem sequence has been specified
23522208Sdavidn		 */
23622208Sdavidn		if (IC) {
23722208Sdavidn			if (!opentty(ttyn, O_RDWR|O_NONBLOCK))
23822208Sdavidn				exit(1);
23922208Sdavidn			setdefttymode(tname);
24022208Sdavidn			if (getty_chat(IC, CT, DC) > 0) {
24122208Sdavidn				syslog(LOG_ERR, "modem init problem on %s", ttyn);
24222491Sdavidn				(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
24322208Sdavidn				exit(1);
2441592Srgrimes			}
2451592Srgrimes		}
24622208Sdavidn
24722208Sdavidn		if (AC) {
24822208Sdavidn			int i, rfds;
24922208Sdavidn			struct timeval timeout;
25022208Sdavidn
25122208Sdavidn			if (!opentty(ttyn, O_RDWR|O_NONBLOCK))
25222208Sdavidn				exit(1);
25322208Sdavidn        		setdefttymode(tname);
25422208Sdavidn        		rfds = 1 << 0;	/* FD_SET */
25522208Sdavidn        		timeout.tv_sec = RT;
25622208Sdavidn        		timeout.tv_usec = 0;
25722208Sdavidn        		i = select(32, (fd_set*)&rfds, (fd_set*)NULL,
25822208Sdavidn        			       (fd_set*)NULL, RT ? &timeout : NULL);
25922208Sdavidn        		if (i < 0) {
26022208Sdavidn				syslog(LOG_ERR, "select %s: %m", ttyn);
26122208Sdavidn			} else if (i == 0) {
26222208Sdavidn				syslog(LOG_NOTICE, "recycle tty %s", ttyn);
26322491Sdavidn				(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
26422208Sdavidn				exit(0);  /* recycle for init */
26522208Sdavidn			}
26622208Sdavidn			i = getty_chat(AC, CT, DC);
26722208Sdavidn			if (i > 0) {
26822208Sdavidn				syslog(LOG_ERR, "modem answer problem on %s", ttyn);
26922491Sdavidn				(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
27022208Sdavidn				exit(1);
27122208Sdavidn			}
27222208Sdavidn		} else { /* blocking open */
27322208Sdavidn			if (!opentty(ttyn, O_RDWR))
27422208Sdavidn				exit(1);
27522208Sdavidn		}
2761592Srgrimes	    }
2771592Srgrimes	}
2781592Srgrimes
27915645Sjoerg	/* Start with default tty settings */
28022208Sdavidn	if (tcgetattr(STDIN_FILENO, &tmode) < 0) {
28122208Sdavidn		syslog(LOG_ERR, "tcgetattr %s: %m", ttyn);
28215645Sjoerg		exit(1);
28315645Sjoerg	}
28415645Sjoerg	/*
28515645Sjoerg	 * Don't rely on the driver too much, and initialize crucial
28615645Sjoerg	 * things according to <sys/ttydefaults.h>.  Avoid clobbering
28715645Sjoerg	 * the c_cc[] settings however, the console drivers might wish
28815645Sjoerg	 * to leave their idea of the preferred VERASE key value
28915645Sjoerg	 * there.
29015645Sjoerg	 */
29115645Sjoerg	tmode.c_iflag = TTYDEF_IFLAG;
29215645Sjoerg	tmode.c_oflag = TTYDEF_OFLAG;
29315645Sjoerg	tmode.c_lflag = TTYDEF_LFLAG;
29415645Sjoerg	tmode.c_cflag = TTYDEF_CFLAG;
29515645Sjoerg	omode = tmode;
29615645Sjoerg
2971592Srgrimes	for (;;) {
2981592Srgrimes
29922491Sdavidn		/*
30022491Sdavidn		 * if a delay was specified then sleep for that
30122491Sdavidn		 * number of seconds before writing the initial prompt
30222491Sdavidn		 */
30322491Sdavidn		if (first_sleep && DE) {
30422491Sdavidn		    sleep(DE);
30522491Sdavidn		    /* remove any noise */
30622491Sdavidn		    (void)tcflush(STDIN_FILENO, TCIOFLUSH);
30722491Sdavidn		}
30822491Sdavidn		first_sleep = 0;
30922491Sdavidn
31022208Sdavidn		setttymode(tname, 0);
3111592Srgrimes		if (AB) {
3121592Srgrimes			tname = autobaud();
3131592Srgrimes			continue;
3141592Srgrimes		}
3151592Srgrimes		if (PS) {
3161592Srgrimes			tname = portselector();
3171592Srgrimes			continue;
3181592Srgrimes		}
3191592Srgrimes		if (CL && *CL)
3201592Srgrimes			putpad(CL);
3211592Srgrimes		edithost(HE);
32221120Smsmith
32322208Sdavidn		/* if this is the first time through this, and an
32422208Sdavidn		   issue file has been given, then send it */
32522208Sdavidn		if (first_time && IF) {
32622208Sdavidn			int fd;
32722208Sdavidn
32822208Sdavidn			if ((fd = open(IF, O_RDONLY)) != -1) {
32922208Sdavidn				char * cp;
33022208Sdavidn
33122208Sdavidn				while ((cp = getline(fd)) != NULL) {
33222208Sdavidn					  putf(cp);
33322208Sdavidn				}
33422208Sdavidn				close(fd);
33522208Sdavidn			}
33622208Sdavidn		}
33722491Sdavidn		first_time = 0;
33822208Sdavidn
3391592Srgrimes		if (IM && *IM)
3401592Srgrimes			putf(IM);
3411592Srgrimes		if (setjmp(timeout)) {
34215659Sache			cfsetispeed(&tmode, B0);
34315659Sache			cfsetospeed(&tmode, B0);
34422208Sdavidn			(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
3451592Srgrimes			exit(1);
3461592Srgrimes		}
3471592Srgrimes		if (TO) {
3481592Srgrimes			signal(SIGALRM, dingdong);
3491592Srgrimes			alarm(TO);
3501592Srgrimes		}
35119697Spst		if ((rval = getname()) == 2) {
35219697Spst			execle(PP, "ppplogin", ttyn, (char *) 0, env);
35319697Spst			syslog(LOG_ERR, "%s: %m", PP);
35419697Spst			exit(1);
35519697Spst		} else if (rval) {
3561592Srgrimes			register int i;
3571592Srgrimes
35815645Sjoerg			oflush();
3591592Srgrimes			alarm(0);
3601592Srgrimes			signal(SIGALRM, SIG_DFL);
3611592Srgrimes			if (name[0] == '-') {
3621592Srgrimes				puts("user names may not start with '-'.");
3631592Srgrimes				continue;
3641592Srgrimes			}
3651592Srgrimes			if (!(upper || lower || digit))
3661592Srgrimes				continue;
36715645Sjoerg			setflags(2);
36815645Sjoerg			if (crmod) {
36915645Sjoerg				tmode.c_iflag |= ICRNL;
37015645Sjoerg				tmode.c_oflag |= ONLCR;
37115645Sjoerg			}
37215645Sjoerg#if REALLY_OLD_TTYS
37315645Sjoerg			if (upper || UC)
37415645Sjoerg				tmode.sg_flags |= LCASE;
37515645Sjoerg			if (lower || LC)
37615645Sjoerg				tmode.sg_flags &= ~LCASE;
37715645Sjoerg#endif
37822208Sdavidn			if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
37922208Sdavidn				syslog(LOG_ERR, "tcsetattr %s: %m", ttyn);
38015645Sjoerg				exit(1);
38115645Sjoerg			}
38215645Sjoerg			signal(SIGINT, SIG_DFL);
3831592Srgrimes			for (i = 0; environ[i] != (char *)0; i++)
3841592Srgrimes				env[i] = environ[i];
3851592Srgrimes			makeenv(&env[i]);
3861592Srgrimes
38715645Sjoerg			limit.rlim_max = RLIM_INFINITY;
38815645Sjoerg			limit.rlim_cur = RLIM_INFINITY;
38915645Sjoerg			(void)setrlimit(RLIMIT_CPU, &limit);
3901592Srgrimes			execle(LO, "login", "-p", name, (char *) 0, env);
3911592Srgrimes			syslog(LOG_ERR, "%s: %m", LO);
3921592Srgrimes			exit(1);
3931592Srgrimes		}
3941592Srgrimes		alarm(0);
3951592Srgrimes		signal(SIGALRM, SIG_DFL);
39615645Sjoerg		signal(SIGINT, SIG_IGN);
3971592Srgrimes		if (NX && *NX)
3981592Srgrimes			tname = NX;
3991592Srgrimes	}
4001592Srgrimes}
4011592Srgrimes
40215645Sjoergstatic int
40322208Sdavidnopentty(const char *ttyn, int flags)
40422208Sdavidn{
40522208Sdavidn	int i, j = 0;
40622208Sdavidn	int failopenlogged = 0;
40722208Sdavidn
40822208Sdavidn	while (j < 10 && (i = open(ttyn, flags)) == -1)
40922208Sdavidn	{
41022208Sdavidn		if (((j % 10) == 0) && (errno != ENXIO || !failopenlogged)) {
41122208Sdavidn			syslog(LOG_ERR, "open %s: %m", ttyn);
41222208Sdavidn			failopenlogged = 1;
41322208Sdavidn		}
41422208Sdavidn		j++;
41522208Sdavidn		sleep(60);
41622208Sdavidn	}
41722208Sdavidn	if (i == -1) {
41822208Sdavidn		syslog(LOG_ERR, "open %s: %m", ttyn);
41922208Sdavidn		return 0;
42022208Sdavidn	}
42122208Sdavidn	else {
42222208Sdavidn		login_tty(i);
42322208Sdavidn		return 1;
42422208Sdavidn	}
42522208Sdavidn}
42622208Sdavidn
42722208Sdavidnstatic void
42822208Sdavidnsetdefttymode(tname)
42922208Sdavidn	const char * tname;
43022208Sdavidn{
43122208Sdavidn	if (tcgetattr(STDIN_FILENO, &tmode) < 0) {
43222208Sdavidn		syslog(LOG_ERR, "tcgetattr %s: %m", ttyn);
43322208Sdavidn		exit(1);
43422208Sdavidn	}
43522208Sdavidn	tmode.c_iflag = TTYDEF_IFLAG;
43622208Sdavidn        tmode.c_oflag = TTYDEF_OFLAG;
43722208Sdavidn        tmode.c_lflag = TTYDEF_LFLAG;
43822208Sdavidn        tmode.c_cflag = TTYDEF_CFLAG;
43922208Sdavidn        omode = tmode;
44022208Sdavidn	setttymode(tname, 1);
44122208Sdavidn}
44222208Sdavidn
44322208Sdavidnstatic void
44422208Sdavidnsetttymode(tname, raw)
44522208Sdavidn	const char * tname;
44622208Sdavidn	int raw;
44722208Sdavidn{
44822208Sdavidn	int off = 0;
44922208Sdavidn
45022208Sdavidn	gettable(tname, tabent);
45122208Sdavidn	if (OPset || EPset || APset)
45222208Sdavidn		APset++, OPset++, EPset++;
45322208Sdavidn	setdefaults();
45422208Sdavidn	(void)tcflush(STDIN_FILENO, TCIOFLUSH);	/* clear out the crap */
45522208Sdavidn	ioctl(STDIN_FILENO, FIONBIO, &off);	/* turn off non-blocking mode */
45622208Sdavidn	ioctl(STDIN_FILENO, FIOASYNC, &off);	/* ditto for async mode */
45722208Sdavidn
45822208Sdavidn	if (IS)
45922208Sdavidn		cfsetispeed(&tmode, speed(IS));
46022208Sdavidn	else if (SP)
46122208Sdavidn		cfsetispeed(&tmode, speed(SP));
46222208Sdavidn	if (OS)
46322208Sdavidn		cfsetospeed(&tmode, speed(OS));
46422208Sdavidn	else if (SP)
46522208Sdavidn		cfsetospeed(&tmode, speed(SP));
46622208Sdavidn	setflags(0);
46722208Sdavidn	setchars();
46822208Sdavidn	if (raw)
46922208Sdavidn		cfmakeraw(&tmode);
47022208Sdavidn	if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
47122208Sdavidn		syslog(LOG_ERR, "tcsetattr %s: %m", ttyn);
47222208Sdavidn		exit(1);
47322208Sdavidn	}
47422208Sdavidn}
47522208Sdavidn
47622208Sdavidn
47722208Sdavidnstatic int
4781592Srgrimesgetname()
4791592Srgrimes{
4801592Srgrimes	register int c;
4811592Srgrimes	register char *np;
48219697Spst	unsigned char cs;
48322208Sdavidn	int ppp_state = 0;
48419697Spst	int ppp_connection = 0;
4851592Srgrimes
4861592Srgrimes	/*
4871592Srgrimes	 * Interrupt may happen if we use CBREAK mode
4881592Srgrimes	 */
4891592Srgrimes	if (setjmp(intrupt)) {
4901592Srgrimes		signal(SIGINT, SIG_IGN);
4911592Srgrimes		return (0);
4921592Srgrimes	}
4931592Srgrimes	signal(SIGINT, interrupt);
49415645Sjoerg	setflags(1);
4951592Srgrimes	prompt();
4962286Sjkh	oflush();
4971592Srgrimes	if (PF > 0) {
4981592Srgrimes		sleep(PF);
4991592Srgrimes		PF = 0;
5001592Srgrimes	}
50122208Sdavidn	if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
50215645Sjoerg		syslog(LOG_ERR, "%s: %m", ttyn);
50315645Sjoerg		exit(1);
50415645Sjoerg	}
5051592Srgrimes	crmod = digit = lower = upper = 0;
5061592Srgrimes	np = name;
5071592Srgrimes	for (;;) {
5081592Srgrimes		oflush();
5091592Srgrimes		if (read(STDIN_FILENO, &cs, 1) <= 0)
5101592Srgrimes			exit(0);
5111592Srgrimes		if ((c = cs&0177) == 0)
5121592Srgrimes			return (0);
51319697Spst
51419697Spst		/* PPP detection state machine..
51519697Spst		   Look for sequences:
51619697Spst		   PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or
51719697Spst		   PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC)
51819697Spst		   See RFC1662.
51919697Spst		   Derived from code from Michael Hancock, <michaelh@cet.co.jp>
52019697Spst		   and Erik 'PPP' Olson, <eriko@wrq.com>
52119697Spst		 */
52219697Spst
52319697Spst		if (PP && (cs == PPP_FRAME)) {
52419697Spst			ppp_state = 1;
52519697Spst		} else if (ppp_state == 1 && cs == PPP_STATION) {
52619697Spst			ppp_state = 2;
52719697Spst		} else if (ppp_state == 2 && cs == PPP_ESCAPE) {
52819697Spst			ppp_state = 3;
52919697Spst		} else if ((ppp_state == 2 && cs == PPP_CONTROL)
53019697Spst			|| (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) {
53119697Spst			ppp_state = 4;
53219697Spst		} else if (ppp_state == 4 && cs == PPP_LCP_HI) {
53319697Spst			ppp_state = 5;
53419697Spst		} else if (ppp_state == 5 && cs == PPP_LCP_LOW) {
53519697Spst			ppp_connection = 1;
53619697Spst			break;
53719697Spst		} else {
53819697Spst			ppp_state = 0;
53919697Spst		}
54019697Spst
54115645Sjoerg		if (c == EOT || c == CTRL('d'))
5421592Srgrimes			exit(1);
54322211Sdavidn		if (c == '\r' || c == '\n' || np >= &name[sizeof name-1]) {
5441592Srgrimes			putf("\r\n");
5451592Srgrimes			break;
5461592Srgrimes		}
5471592Srgrimes		if (islower(c))
5481592Srgrimes			lower = 1;
5491592Srgrimes		else if (isupper(c))
5501592Srgrimes			upper = 1;
5512286Sjkh		else if (c == ERASE || c == '\b' || c == 0177) {
5521592Srgrimes			if (np > name) {
5531592Srgrimes				np--;
55415645Sjoerg				if (cfgetospeed(&tmode) >= 1200)
5551592Srgrimes					puts("\b \b");
5561592Srgrimes				else
5571592Srgrimes					putchr(cs);
5581592Srgrimes			}
5591592Srgrimes			continue;
56015645Sjoerg		} else if (c == KILL || c == CTRL('u')) {
5611592Srgrimes			putchr('\r');
56215645Sjoerg			if (cfgetospeed(&tmode) < 1200)
5631592Srgrimes				putchr('\n');
5641592Srgrimes			/* this is the way they do it down under ... */
5651592Srgrimes			else if (np > name)
5661592Srgrimes				puts("                                     \r");
5671592Srgrimes			prompt();
5681592Srgrimes			np = name;
5691592Srgrimes			continue;
5701592Srgrimes		} else if (isdigit(c))
5711592Srgrimes			digit++;
5721592Srgrimes		if (IG && (c <= ' ' || c > 0176))
5731592Srgrimes			continue;
5741592Srgrimes		*np++ = c;
5751592Srgrimes		putchr(cs);
5761592Srgrimes	}
5771592Srgrimes	signal(SIGINT, SIG_IGN);
5781592Srgrimes	*np = 0;
5791592Srgrimes	if (c == '\r')
5801592Srgrimes		crmod = 1;
58115645Sjoerg	if ((upper && !lower && !LC) || UC)
5821592Srgrimes		for (np = name; *np; np++)
5831592Srgrimes			if (isupper(*np))
5841592Srgrimes				*np = tolower(*np);
58519697Spst	return (1 + ppp_connection);
5861592Srgrimes}
5871592Srgrimes
58815645Sjoergstatic void
5891592Srgrimesputpad(s)
59015645Sjoerg	register const char *s;
5911592Srgrimes{
5921592Srgrimes	register pad = 0;
59315645Sjoerg	speed_t ospeed = cfgetospeed(&tmode);
5941592Srgrimes
5951592Srgrimes	if (isdigit(*s)) {
5961592Srgrimes		while (isdigit(*s)) {
5971592Srgrimes			pad *= 10;
5981592Srgrimes			pad += *s++ - '0';
5991592Srgrimes		}
6001592Srgrimes		pad *= 10;
6011592Srgrimes		if (*s == '.' && isdigit(s[1])) {
6021592Srgrimes			pad += s[1] - '0';
6031592Srgrimes			s += 2;
6041592Srgrimes		}
6051592Srgrimes	}
6061592Srgrimes
6071592Srgrimes	puts(s);
6081592Srgrimes	/*
6091592Srgrimes	 * If no delay needed, or output speed is
6101592Srgrimes	 * not comprehensible, then don't try to delay.
6111592Srgrimes	 */
61215645Sjoerg	if (pad == 0 || ospeed <= 0)
6131592Srgrimes		return;
6141592Srgrimes
6151592Srgrimes	/*
6161592Srgrimes	 * Round up by a half a character frame, and then do the delay.
6171592Srgrimes	 * Too bad there are no user program accessible programmed delays.
6181592Srgrimes	 * Transmitting pad characters slows many terminals down and also
6191592Srgrimes	 * loads the system.
6201592Srgrimes	 */
62115645Sjoerg	pad = (pad * ospeed + 50000) / 100000;
62215645Sjoerg	while (pad--)
6231592Srgrimes		putchr(*PC);
6241592Srgrimes}
6251592Srgrimes
62615645Sjoergstatic void
6271592Srgrimesputs(s)
62815645Sjoerg	register const char *s;
6291592Srgrimes{
6301592Srgrimes	while (*s)
6311592Srgrimes		putchr(*s++);
6321592Srgrimes}
6331592Srgrimes
6341592Srgrimeschar	outbuf[OBUFSIZ];
6351592Srgrimesint	obufcnt = 0;
6361592Srgrimes
63715645Sjoergstatic void
6381592Srgrimesputchr(cc)
63915645Sjoerg	int cc;
6401592Srgrimes{
6411592Srgrimes	char c;
6421592Srgrimes
6431592Srgrimes	c = cc;
6441592Srgrimes	if (!NP) {
6451592Srgrimes		c |= partab[c&0177] & 0200;
6461592Srgrimes		if (OP)
6471592Srgrimes			c ^= 0200;
6481592Srgrimes	}
6491592Srgrimes	if (!UB) {
6501592Srgrimes		outbuf[obufcnt++] = c;
6511592Srgrimes		if (obufcnt >= OBUFSIZ)
6521592Srgrimes			oflush();
6531592Srgrimes	} else
6541592Srgrimes		write(STDOUT_FILENO, &c, 1);
6551592Srgrimes}
6561592Srgrimes
65715645Sjoergstatic void
6581592Srgrimesoflush()
6591592Srgrimes{
6601592Srgrimes	if (obufcnt)
6611592Srgrimes		write(STDOUT_FILENO, outbuf, obufcnt);
6621592Srgrimes	obufcnt = 0;
6631592Srgrimes}
6641592Srgrimes
66515645Sjoergstatic void
6661592Srgrimesprompt()
6671592Srgrimes{
6681592Srgrimes
6691592Srgrimes	putf(LM);
6701592Srgrimes	if (CO)
6711592Srgrimes		putchr('\n');
6721592Srgrimes}
6731592Srgrimes
67422208Sdavidn
67522208Sdavidnstatic char *
67622208Sdavidngetline(fd)
67722208Sdavidn	int fd;
67822208Sdavidn{
67922208Sdavidn	int i = 0;
68022208Sdavidn	static char linebuf[512];
68122208Sdavidn
68222208Sdavidn	/*
68322208Sdavidn	 * This is certainly slow, but it avoids having to include
68422208Sdavidn	 * stdio.h unnecessarily. Issue files should be small anyway.
68522208Sdavidn	 */
68622208Sdavidn	while (i < (sizeof linebuf - 3) && read(fd, linebuf+i, 1)==1) {
68722208Sdavidn		if (linebuf[i] == '\n') {
68822208Sdavidn			/* Don't rely on newline mode, assume raw */
68922208Sdavidn			linebuf[i++] = '\r';
69022208Sdavidn			linebuf[i++] = '\n';
69122208Sdavidn			linebuf[i] = '\0';
69222208Sdavidn			return linebuf;
69322208Sdavidn		}
69422208Sdavidn		++i;
69522208Sdavidn	}
69622208Sdavidn	linebuf[i] = '\0';
69722208Sdavidn	return i ? linebuf : 0;
69822208Sdavidn}
69922208Sdavidn
70015645Sjoergstatic void
7011592Srgrimesputf(cp)
70215645Sjoerg	register const char *cp;
7031592Srgrimes{
7041592Srgrimes	extern char editedhost[];
7051592Srgrimes	time_t t;
7061592Srgrimes	char *slash, db[100];
7071592Srgrimes
70822199Sdavidn	static struct utsname kerninfo;
70922199Sdavidn
71022199Sdavidn	if (!*kerninfo.sysname)
71122199Sdavidn		uname(&kerninfo);
71222199Sdavidn
7131592Srgrimes	while (*cp) {
7141592Srgrimes		if (*cp != '%') {
7151592Srgrimes			putchr(*cp++);
7161592Srgrimes			continue;
7171592Srgrimes		}
7181592Srgrimes		switch (*++cp) {
7191592Srgrimes
7201592Srgrimes		case 't':
72115645Sjoerg			slash = strrchr(ttyn, '/');
7221592Srgrimes			if (slash == (char *) 0)
7231592Srgrimes				puts(ttyn);
7241592Srgrimes			else
7251592Srgrimes				puts(&slash[1]);
7261592Srgrimes			break;
7271592Srgrimes
7281592Srgrimes		case 'h':
7291592Srgrimes			puts(editedhost);
7301592Srgrimes			break;
7311592Srgrimes
7321592Srgrimes		case 'd': {
73315645Sjoerg			t = (time_t)0;
7341592Srgrimes			(void)time(&t);
73515645Sjoerg			if (Lo)
73615645Sjoerg				(void)setlocale(LC_TIME, Lo);
73715645Sjoerg			(void)strftime(db, sizeof(db), "%+", localtime(&t));
7381592Srgrimes			puts(db);
7399875Sjkh			break;
74015645Sjoerg
74115645Sjoerg		case 's':
74215645Sjoerg			puts(kerninfo.sysname);
74315645Sjoerg			break;
74415645Sjoerg
74515645Sjoerg		case 'm':
74615645Sjoerg			puts(kerninfo.machine);
74715645Sjoerg			break;
74815645Sjoerg
74915645Sjoerg		case 'r':
75015645Sjoerg			puts(kerninfo.release);
75115645Sjoerg			break;
75215645Sjoerg
75315645Sjoerg		case 'v':
75415645Sjoerg			puts(kerninfo.version);
75515645Sjoerg			break;
7561592Srgrimes		}
7571592Srgrimes
7581592Srgrimes		case '%':
7591592Srgrimes			putchr('%');
7601592Srgrimes			break;
7611592Srgrimes		}
7621592Srgrimes		cp++;
7631592Srgrimes	}
7641592Srgrimes}
765