xref: /csrg-svn/libexec/getty/main.c (revision 60499)
146043Sbostic /*-
246043Sbostic  * Copyright (c) 1980 The Regents of the University of California.
346043Sbostic  * All rights reserved.
446043Sbostic  *
546043Sbostic  * %sccs.include.redist.c%
619054Sdist  */
719054Sdist 
813795Ssam #ifndef lint
919054Sdist char copyright[] =
1046043Sbostic "@(#) Copyright (c) 1980 The Regents of the University of California.\n\
1119054Sdist  All rights reserved.\n";
1246043Sbostic #endif /* not lint */
1313795Ssam 
1419054Sdist #ifndef lint
15*60499Selan static char sccsid[] = "@(#)main.c	5.20 (Berkeley) 05/27/93";
1646043Sbostic #endif /* not lint */
1719054Sdist 
1846043Sbostic #define USE_OLD_TTY
1913795Ssam 
2042459Smarc #include <sys/param.h>
2146670Sbostic #include <sys/stat.h>
2260091Sbostic 
2360091Sbostic #include <ctype.h>
2460091Sbostic #include <ctype.h>
2546670Sbostic #include <fcntl.h>
2660091Sbostic #include <setjmp.h>
2713795Ssam #include <sgtty.h>
2860091Sbostic #include <signal.h>
2960091Sbostic #include <stdlib.h>
3060091Sbostic #include <string.h>
3160091Sbostic #include <syslog.h>
3246670Sbostic #include <time.h>
3346043Sbostic #include <unistd.h>
3460091Sbostic 
3513795Ssam #include "gettytab.h"
3642459Smarc #include "pathnames.h"
3760091Sbostic #include "extern.h"
3813795Ssam 
3913795Ssam struct	sgttyb tmode = {
4013795Ssam 	0, 0, CERASE, CKILL, 0
4113795Ssam };
4213795Ssam struct	tchars tc = {
4313795Ssam 	CINTR, CQUIT, CSTART,
4413795Ssam 	CSTOP, CEOF, CBRK,
4513795Ssam };
4613795Ssam struct	ltchars ltc = {
4713795Ssam 	CSUSP, CDSUSP, CRPRNT,
4813795Ssam 	CFLUSH, CWERASE, CLNEXT
4913795Ssam };
5013795Ssam 
5146043Sbostic int crmod, digit, lower, upper;
5213795Ssam 
5342459Smarc char	hostname[MAXHOSTNAMELEN];
5413795Ssam char	name[16];
5542459Smarc char	dev[] = _PATH_DEV;
5618543Sralph char	ttyn[32];
5713795Ssam char	*portselector();
5818543Sralph char	*ttyname();
5913795Ssam 
6013828Skre #define	OBUFSIZ		128
6113795Ssam #define	TABBUFSIZ	512
6213795Ssam 
6313795Ssam char	defent[TABBUFSIZ];
6413795Ssam char	tabent[TABBUFSIZ];
6513795Ssam 
6613795Ssam char	*env[128];
6713795Ssam 
6813795Ssam char partab[] = {
6913795Ssam 	0001,0201,0201,0001,0201,0001,0001,0201,
7013795Ssam 	0202,0004,0003,0205,0005,0206,0201,0001,
7113795Ssam 	0201,0001,0001,0201,0001,0201,0201,0001,
7213795Ssam 	0001,0201,0201,0001,0201,0001,0001,0201,
7313795Ssam 	0200,0000,0000,0200,0000,0200,0200,0000,
7413795Ssam 	0000,0200,0200,0000,0200,0000,0000,0200,
7513795Ssam 	0000,0200,0200,0000,0200,0000,0000,0200,
7613795Ssam 	0200,0000,0000,0200,0000,0200,0200,0000,
7713795Ssam 	0200,0000,0000,0200,0000,0200,0200,0000,
7813795Ssam 	0000,0200,0200,0000,0200,0000,0000,0200,
7913795Ssam 	0000,0200,0200,0000,0200,0000,0000,0200,
8013795Ssam 	0200,0000,0000,0200,0000,0200,0200,0000,
8113795Ssam 	0000,0200,0200,0000,0200,0000,0000,0200,
8213795Ssam 	0200,0000,0000,0200,0000,0200,0200,0000,
8313795Ssam 	0200,0000,0000,0200,0000,0200,0200,0000,
8413795Ssam 	0000,0200,0200,0000,0200,0000,0000,0201
8513795Ssam };
8613795Ssam 
8713795Ssam #define	ERASE	tmode.sg_erase
8813795Ssam #define	KILL	tmode.sg_kill
8913795Ssam #define	EOT	tc.t_eofc
9013795Ssam 
9113795Ssam jmp_buf timeout;
9213795Ssam 
9346670Sbostic static void
9413795Ssam dingdong()
9513795Ssam {
9613795Ssam 
9713795Ssam 	alarm(0);
9813795Ssam 	signal(SIGALRM, SIG_DFL);
9913795Ssam 	longjmp(timeout, 1);
10013795Ssam }
10113795Ssam 
10213828Skre jmp_buf	intrupt;
10313828Skre 
10446670Sbostic static void
10513828Skre interrupt()
10613828Skre {
10713828Skre 
10813828Skre 	signal(SIGINT, interrupt);
10913828Skre 	longjmp(intrupt, 1);
11013828Skre }
11113828Skre 
11260091Sbostic static int	getname __P((void));
11360091Sbostic static void	oflush __P((void));
11460091Sbostic static void	prompt __P((void));
11560091Sbostic static void	putchr __P((int));
11660091Sbostic static void	putf __P((char *));
11760091Sbostic static void	putpad __P((char *));
11860091Sbostic static void	puts __P((char *));
11960091Sbostic 
12060091Sbostic int
12113795Ssam main(argc, argv)
12246043Sbostic 	int argc;
12360091Sbostic 	char *argv[];
12413795Ssam {
12560091Sbostic 	extern char **environ;
12613795Ssam 	char *tname;
12713795Ssam 	long allflags;
12818543Sralph 	int repcnt = 0;
12913795Ssam 
13013828Skre 	signal(SIGINT, SIG_IGN);
13113795Ssam /*
13213795Ssam 	signal(SIGQUIT, SIG_DFL);
13313795Ssam */
13424890Seric 	openlog("getty", LOG_ODELAY|LOG_CONS, LOG_AUTH);
13513795Ssam 	gethostname(hostname, sizeof(hostname));
13613795Ssam 	if (hostname[0] == '\0')
13713795Ssam 		strcpy(hostname, "Amnesiac");
13818543Sralph 	/*
13918543Sralph 	 * The following is a work around for vhangup interactions
14018543Sralph 	 * which cause great problems getting window systems started.
14118543Sralph 	 * If the tty line is "-", we do the old style getty presuming
14218543Sralph 	 * that the file descriptors are already set up for us.
14318543Sralph 	 * J. Gettys - MIT Project Athena.
14418543Sralph 	 */
14518543Sralph 	if (argc <= 2 || strcmp(argv[2], "-") == 0)
14625954Sbloom 	    strcpy(ttyn, ttyname(0));
14718543Sralph 	else {
14844567Smarc 	    int i;
14944567Smarc 
15025954Sbloom 	    strcpy(ttyn, dev);
15125954Sbloom 	    strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
15225954Sbloom 	    if (strcmp(argv[0], "+") != 0) {
15318543Sralph 		chown(ttyn, 0, 0);
15444567Smarc 		chmod(ttyn, 0600);
15544567Smarc 		revoke(ttyn);
15625553Smckusick 		/*
15725553Smckusick 		 * Delay the open so DTR stays down long enough to be detected.
15825553Smckusick 		 */
15925553Smckusick 		sleep(2);
16044567Smarc 		while ((i = open(ttyn, O_RDWR)) == -1) {
16118543Sralph 			if (repcnt % 10 == 0) {
16224895Seric 				syslog(LOG_ERR, "%s: %m", ttyn);
16318543Sralph 				closelog();
16418543Sralph 			}
16518543Sralph 			repcnt++;
16618543Sralph 			sleep(60);
16718543Sralph 		}
16844567Smarc 		login_tty(i);
16925954Sbloom 	    }
17018543Sralph 	}
17118543Sralph 
172*60499Selan 	gettable("default", defent);
17313795Ssam 	gendefaults();
17413795Ssam 	tname = "default";
17513795Ssam 	if (argc > 1)
17613795Ssam 		tname = argv[1];
17713795Ssam 	for (;;) {
17853076Sbostic 		int off;
17913795Ssam 
180*60499Selan 		gettable(tname, tabent);
18113828Skre 		if (OPset || EPset || APset)
18213828Skre 			APset++, OPset++, EPset++;
18313795Ssam 		setdefaults();
18453076Sbostic 		off = 0;
18553076Sbostic 		ioctl(0, TIOCFLUSH, &off);	/* clear out the crap */
18632209Sbostic 		ioctl(0, FIONBIO, &off);	/* turn off non-blocking mode */
18746043Sbostic 		ioctl(0, FIOASYNC, &off);	/* ditto for async mode */
18813795Ssam 		if (IS)
18913795Ssam 			tmode.sg_ispeed = speed(IS);
19013795Ssam 		else if (SP)
19113795Ssam 			tmode.sg_ispeed = speed(SP);
19213795Ssam 		if (OS)
19313795Ssam 			tmode.sg_ospeed = speed(OS);
19413795Ssam 		else if (SP)
19513795Ssam 			tmode.sg_ospeed = speed(SP);
19613795Ssam 		tmode.sg_flags = setflags(0);
19713795Ssam 		ioctl(0, TIOCSETP, &tmode);
19813795Ssam 		setchars();
19913795Ssam 		ioctl(0, TIOCSETC, &tc);
20013795Ssam 		if (HC)
20113795Ssam 			ioctl(0, TIOCHPCL, 0);
20218543Sralph 		if (AB) {
20318543Sralph 			extern char *autobaud();
20418543Sralph 
20518543Sralph 			tname = autobaud();
20618543Sralph 			continue;
20718543Sralph 		}
20813795Ssam 		if (PS) {
20913795Ssam 			tname = portselector();
21013795Ssam 			continue;
21113795Ssam 		}
21213795Ssam 		if (CL && *CL)
21313795Ssam 			putpad(CL);
21413795Ssam 		edithost(HE);
21513795Ssam 		if (IM && *IM)
21613795Ssam 			putf(IM);
21713795Ssam 		if (setjmp(timeout)) {
21813795Ssam 			tmode.sg_ispeed = tmode.sg_ospeed = 0;
21913795Ssam 			ioctl(0, TIOCSETP, &tmode);
22013795Ssam 			exit(1);
22113795Ssam 		}
22213795Ssam 		if (TO) {
22313795Ssam 			signal(SIGALRM, dingdong);
22413795Ssam 			alarm(TO);
22513795Ssam 		}
22613795Ssam 		if (getname()) {
22718543Sralph 			register int i;
22818543Sralph 
22918543Sralph 			oflush();
23013795Ssam 			alarm(0);
23113795Ssam 			signal(SIGALRM, SIG_DFL);
23232308Sbostic 			if (name[0] == '-') {
23342459Smarc 				puts("user names may not start with '-'.");
23432308Sbostic 				continue;
23532308Sbostic 			}
23613831Ssam 			if (!(upper || lower || digit))
23713795Ssam 				continue;
23813795Ssam 			allflags = setflags(2);
23913795Ssam 			tmode.sg_flags = allflags & 0xffff;
24013795Ssam 			allflags >>= 16;
24113795Ssam 			if (crmod || NL)
24213795Ssam 				tmode.sg_flags |= CRMOD;
24313795Ssam 			if (upper || UC)
24413795Ssam 				tmode.sg_flags |= LCASE;
24513795Ssam 			if (lower || LC)
24613795Ssam 				tmode.sg_flags &= ~LCASE;
24713795Ssam 			ioctl(0, TIOCSETP, &tmode);
24813795Ssam 			ioctl(0, TIOCSLTC, &ltc);
24913795Ssam 			ioctl(0, TIOCLSET, &allflags);
25013828Skre 			signal(SIGINT, SIG_DFL);
25118543Sralph 			for (i = 0; environ[i] != (char *)0; i++)
25218543Sralph 				env[i] = environ[i];
25318543Sralph 			makeenv(&env[i]);
25444640Smarc 
25544640Smarc 			/*
25644640Smarc 			 * this is what login was doing anyway.
25744640Smarc 			 * soon we rewrite getty completely.
25844640Smarc 			 */
25944640Smarc 			set_ttydefaults(0);
26018543Sralph 			execle(LO, "login", "-p", name, (char *) 0, env);
26132209Sbostic 			syslog(LOG_ERR, "%s: %m", LO);
26213795Ssam 			exit(1);
26313795Ssam 		}
26413795Ssam 		alarm(0);
26513795Ssam 		signal(SIGALRM, SIG_DFL);
26613828Skre 		signal(SIGINT, SIG_IGN);
26713795Ssam 		if (NX && *NX)
26813795Ssam 			tname = NX;
26913795Ssam 	}
27013795Ssam }
27113795Ssam 
27260091Sbostic static int
27313795Ssam getname()
27413795Ssam {
27546043Sbostic 	register int c;
27613795Ssam 	register char *np;
27713795Ssam 	char cs;
27813795Ssam 
27913828Skre 	/*
28013831Ssam 	 * Interrupt may happen if we use CBREAK mode
28113828Skre 	 */
28213828Skre 	if (setjmp(intrupt)) {
28313828Skre 		signal(SIGINT, SIG_IGN);
28413828Skre 		return (0);
28513828Skre 	}
28613828Skre 	signal(SIGINT, interrupt);
28713795Ssam 	tmode.sg_flags = setflags(0);
28813795Ssam 	ioctl(0, TIOCSETP, &tmode);
28913795Ssam 	tmode.sg_flags = setflags(1);
29013795Ssam 	prompt();
29113885Ssam 	if (PF > 0) {
29214322Ssam 		oflush();
29313885Ssam 		sleep(PF);
29413885Ssam 		PF = 0;
29513885Ssam 	}
29613795Ssam 	ioctl(0, TIOCSETP, &tmode);
29746043Sbostic 	crmod = digit = lower = upper = 0;
29813795Ssam 	np = name;
29913795Ssam 	for (;;) {
30013828Skre 		oflush();
30146043Sbostic 		if (read(STDIN_FILENO, &cs, 1) <= 0)
30213795Ssam 			exit(0);
30313795Ssam 		if ((c = cs&0177) == 0)
30413795Ssam 			return (0);
30513831Ssam 		if (c == EOT)
30613795Ssam 			exit(1);
30718543Sralph 		if (c == '\r' || c == '\n' || np >= &name[sizeof name]) {
30818543Sralph 			putf("\r\n");
30913795Ssam 			break;
31018543Sralph 		}
31142459Smarc 		if (islower(c))
31246043Sbostic 			lower = 1;
31342459Smarc 		else if (isupper(c))
31446043Sbostic 			upper = 1;
31518543Sralph 		else if (c == ERASE || c == '#' || c == '\b') {
31613795Ssam 			if (np > name) {
31713795Ssam 				np--;
31813795Ssam 				if (tmode.sg_ospeed >= B1200)
31913795Ssam 					puts("\b \b");
32013795Ssam 				else
32113795Ssam 					putchr(cs);
32213795Ssam 			}
32313795Ssam 			continue;
32413831Ssam 		} else if (c == KILL || c == '@') {
32513795Ssam 			putchr(cs);
32613795Ssam 			putchr('\r');
32713795Ssam 			if (tmode.sg_ospeed < B1200)
32813795Ssam 				putchr('\n');
32913795Ssam 			/* this is the way they do it down under ... */
33013795Ssam 			else if (np > name)
33113795Ssam 				puts("                                     \r");
33213795Ssam 			prompt();
33313795Ssam 			np = name;
33413795Ssam 			continue;
33542459Smarc 		} else if (isdigit(c))
33613795Ssam 			digit++;
33718543Sralph 		if (IG && (c <= ' ' || c > 0176))
33813795Ssam 			continue;
33913795Ssam 		*np++ = c;
34013795Ssam 		putchr(cs);
34113795Ssam 	}
34213828Skre 	signal(SIGINT, SIG_IGN);
34313795Ssam 	*np = 0;
34413795Ssam 	if (c == '\r')
34546043Sbostic 		crmod = 1;
34613795Ssam 	if (upper && !lower && !LC || UC)
34713795Ssam 		for (np = name; *np; np++)
34813795Ssam 			if (isupper(*np))
34913795Ssam 				*np = tolower(*np);
35013795Ssam 	return (1);
35113795Ssam }
35213795Ssam 
35313795Ssam static
35413795Ssam short	tmspc10[] = {
35513795Ssam 	0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5, 15
35613795Ssam };
35713795Ssam 
35860091Sbostic static void
35913795Ssam putpad(s)
36013795Ssam 	register char *s;
36113795Ssam {
36213795Ssam 	register pad = 0;
36313795Ssam 	register mspc10;
36413795Ssam 
36513795Ssam 	if (isdigit(*s)) {
36613795Ssam 		while (isdigit(*s)) {
36713795Ssam 			pad *= 10;
36813795Ssam 			pad += *s++ - '0';
36913795Ssam 		}
37013795Ssam 		pad *= 10;
37113795Ssam 		if (*s == '.' && isdigit(s[1])) {
37213795Ssam 			pad += s[1] - '0';
37313795Ssam 			s += 2;
37413795Ssam 		}
37513795Ssam 	}
37613795Ssam 
37713795Ssam 	puts(s);
37813795Ssam 	/*
37913795Ssam 	 * If no delay needed, or output speed is
38013795Ssam 	 * not comprehensible, then don't try to delay.
38113795Ssam 	 */
38213795Ssam 	if (pad == 0)
38313795Ssam 		return;
38413795Ssam 	if (tmode.sg_ospeed <= 0 ||
38513795Ssam 	    tmode.sg_ospeed >= (sizeof tmspc10 / sizeof tmspc10[0]))
38613795Ssam 		return;
38713795Ssam 
38813795Ssam 	/*
38946043Sbostic 	 * Round up by a half a character frame, and then do the delay.
39013795Ssam 	 * Too bad there are no user program accessible programmed delays.
39146043Sbostic 	 * Transmitting pad characters slows many terminals down and also
39246043Sbostic 	 * loads the system.
39313795Ssam 	 */
39413795Ssam 	mspc10 = tmspc10[tmode.sg_ospeed];
39513795Ssam 	pad += mspc10 / 2;
39613795Ssam 	for (pad /= mspc10; pad > 0; pad--)
39713795Ssam 		putchr(*PC);
39813795Ssam }
39913795Ssam 
40060091Sbostic static void
40113795Ssam puts(s)
40213795Ssam 	register char *s;
40313795Ssam {
40413795Ssam 	while (*s)
40513795Ssam 		putchr(*s++);
40613795Ssam }
40713795Ssam 
40813828Skre char	outbuf[OBUFSIZ];
40913828Skre int	obufcnt = 0;
41013828Skre 
41160091Sbostic static void
41213795Ssam putchr(cc)
41360091Sbostic 	int cc;
41413795Ssam {
41513795Ssam 	char c;
41613795Ssam 
41713795Ssam 	c = cc;
41847664Swilliam 	if (!NP) {
41947664Swilliam 		c |= partab[c&0177] & 0200;
42047664Swilliam 		if (OP)
42147664Swilliam 			c ^= 0200;
42247664Swilliam 	}
42313828Skre 	if (!UB) {
42413828Skre 		outbuf[obufcnt++] = c;
42513828Skre 		if (obufcnt >= OBUFSIZ)
42613828Skre 			oflush();
42713828Skre 	} else
42846043Sbostic 		write(STDOUT_FILENO, &c, 1);
42913795Ssam }
43013795Ssam 
43160091Sbostic static void
43213828Skre oflush()
43313828Skre {
43413828Skre 	if (obufcnt)
43546043Sbostic 		write(STDOUT_FILENO, outbuf, obufcnt);
43613828Skre 	obufcnt = 0;
43713828Skre }
43813828Skre 
43960091Sbostic static void
44013795Ssam prompt()
44113795Ssam {
44213795Ssam 
44313795Ssam 	putf(LM);
44413795Ssam 	if (CO)
44513795Ssam 		putchr('\n');
44613795Ssam }
44713795Ssam 
44860091Sbostic static void
44913795Ssam putf(cp)
45013795Ssam 	register char *cp;
45113795Ssam {
45213795Ssam 	extern char editedhost[];
45346043Sbostic 	time_t t;
45446670Sbostic 	char *slash, db[100];
45513795Ssam 
45613795Ssam 	while (*cp) {
45713795Ssam 		if (*cp != '%') {
45813795Ssam 			putchr(*cp++);
45913795Ssam 			continue;
46013795Ssam 		}
46113795Ssam 		switch (*++cp) {
46213795Ssam 
46318543Sralph 		case 't':
46460091Sbostic 			slash = strrchr(ttyn, '/');
46518543Sralph 			if (slash == (char *) 0)
46618543Sralph 				puts(ttyn);
46718543Sralph 			else
46818543Sralph 				puts(&slash[1]);
46918543Sralph 			break;
47018543Sralph 
47113795Ssam 		case 'h':
47213795Ssam 			puts(editedhost);
47313795Ssam 			break;
47413795Ssam 
47546670Sbostic 		case 'd': {
47646967Sbostic 			static char fmt[] = "%l:% %P on %A, %d %B %Y";
47746670Sbostic 
47846670Sbostic 			fmt[4] = 'M';		/* I *hate* SCCS... */
47946043Sbostic 			(void)time(&t);
48046670Sbostic 			(void)strftime(db, sizeof(db), fmt, localtime(&t));
48146043Sbostic 			puts(db);
48215713Sralph 			break;
48346670Sbostic 		}
48415713Sralph 
48513795Ssam 		case '%':
48613795Ssam 			putchr('%');
48713795Ssam 			break;
48813795Ssam 		}
48913795Ssam 		cp++;
49013795Ssam 	}
49113795Ssam }
492