xref: /csrg-svn/libexec/getty/main.c (revision 47664)
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*47664Swilliam static char sccsid[] = "@(#)main.c	5.16 (Berkeley) 03/27/91";
1646043Sbostic #endif /* not lint */
1719054Sdist 
1846043Sbostic #define USE_OLD_TTY
1913795Ssam 
2042459Smarc #include <sys/param.h>
2146670Sbostic #include <sys/stat.h>
2246670Sbostic #include <signal.h>
2346670Sbostic #include <fcntl.h>
2413795Ssam #include <sgtty.h>
2546670Sbostic #include <time.h>
2613795Ssam #include <ctype.h>
2713795Ssam #include <setjmp.h>
2818543Sralph #include <syslog.h>
2946043Sbostic #include <unistd.h>
3042459Smarc #include <ctype.h>
3146670Sbostic #include <stdlib.h>
3246043Sbostic #include <string.h>
3313795Ssam #include "gettytab.h"
3442459Smarc #include "pathnames.h"
3513795Ssam 
3613795Ssam struct	sgttyb tmode = {
3713795Ssam 	0, 0, CERASE, CKILL, 0
3813795Ssam };
3913795Ssam struct	tchars tc = {
4013795Ssam 	CINTR, CQUIT, CSTART,
4113795Ssam 	CSTOP, CEOF, CBRK,
4213795Ssam };
4313795Ssam struct	ltchars ltc = {
4413795Ssam 	CSUSP, CDSUSP, CRPRNT,
4513795Ssam 	CFLUSH, CWERASE, CLNEXT
4613795Ssam };
4713795Ssam 
4846043Sbostic int crmod, digit, lower, upper;
4913795Ssam 
5042459Smarc char	hostname[MAXHOSTNAMELEN];
5113795Ssam char	name[16];
5242459Smarc char	dev[] = _PATH_DEV;
5318543Sralph char	ttyn[32];
5413795Ssam char	*portselector();
5518543Sralph char	*ttyname();
5613795Ssam 
5713828Skre #define	OBUFSIZ		128
5813795Ssam #define	TABBUFSIZ	512
5913795Ssam 
6013795Ssam char	defent[TABBUFSIZ];
6113795Ssam char	defstrs[TABBUFSIZ];
6213795Ssam char	tabent[TABBUFSIZ];
6313795Ssam char	tabstrs[TABBUFSIZ];
6413795Ssam 
6513795Ssam char	*env[128];
6613795Ssam 
6713795Ssam char partab[] = {
6813795Ssam 	0001,0201,0201,0001,0201,0001,0001,0201,
6913795Ssam 	0202,0004,0003,0205,0005,0206,0201,0001,
7013795Ssam 	0201,0001,0001,0201,0001,0201,0201,0001,
7113795Ssam 	0001,0201,0201,0001,0201,0001,0001,0201,
7213795Ssam 	0200,0000,0000,0200,0000,0200,0200,0000,
7313795Ssam 	0000,0200,0200,0000,0200,0000,0000,0200,
7413795Ssam 	0000,0200,0200,0000,0200,0000,0000,0200,
7513795Ssam 	0200,0000,0000,0200,0000,0200,0200,0000,
7613795Ssam 	0200,0000,0000,0200,0000,0200,0200,0000,
7713795Ssam 	0000,0200,0200,0000,0200,0000,0000,0200,
7813795Ssam 	0000,0200,0200,0000,0200,0000,0000,0200,
7913795Ssam 	0200,0000,0000,0200,0000,0200,0200,0000,
8013795Ssam 	0000,0200,0200,0000,0200,0000,0000,0200,
8113795Ssam 	0200,0000,0000,0200,0000,0200,0200,0000,
8213795Ssam 	0200,0000,0000,0200,0000,0200,0200,0000,
8313795Ssam 	0000,0200,0200,0000,0200,0000,0000,0201
8413795Ssam };
8513795Ssam 
8613795Ssam #define	ERASE	tmode.sg_erase
8713795Ssam #define	KILL	tmode.sg_kill
8813795Ssam #define	EOT	tc.t_eofc
8913795Ssam 
9013795Ssam jmp_buf timeout;
9113795Ssam 
9246670Sbostic static void
9313795Ssam dingdong()
9413795Ssam {
9513795Ssam 
9613795Ssam 	alarm(0);
9713795Ssam 	signal(SIGALRM, SIG_DFL);
9813795Ssam 	longjmp(timeout, 1);
9913795Ssam }
10013795Ssam 
10113828Skre jmp_buf	intrupt;
10213828Skre 
10346670Sbostic static void
10413828Skre interrupt()
10513828Skre {
10613828Skre 
10713828Skre 	signal(SIGINT, interrupt);
10813828Skre 	longjmp(intrupt, 1);
10913828Skre }
11013828Skre 
11113795Ssam main(argc, argv)
11246043Sbostic 	int argc;
11346043Sbostic 	char **argv;
11413795Ssam {
11546043Sbostic 	extern	char **environ;
11613795Ssam 	char *tname;
11713795Ssam 	long allflags;
11818543Sralph 	int repcnt = 0;
11913795Ssam 
12013828Skre 	signal(SIGINT, SIG_IGN);
12113795Ssam /*
12213795Ssam 	signal(SIGQUIT, SIG_DFL);
12313795Ssam */
12424890Seric 	openlog("getty", LOG_ODELAY|LOG_CONS, LOG_AUTH);
12513795Ssam 	gethostname(hostname, sizeof(hostname));
12613795Ssam 	if (hostname[0] == '\0')
12713795Ssam 		strcpy(hostname, "Amnesiac");
12818543Sralph 	/*
12918543Sralph 	 * The following is a work around for vhangup interactions
13018543Sralph 	 * which cause great problems getting window systems started.
13118543Sralph 	 * If the tty line is "-", we do the old style getty presuming
13218543Sralph 	 * that the file descriptors are already set up for us.
13318543Sralph 	 * J. Gettys - MIT Project Athena.
13418543Sralph 	 */
13518543Sralph 	if (argc <= 2 || strcmp(argv[2], "-") == 0)
13625954Sbloom 	    strcpy(ttyn, ttyname(0));
13718543Sralph 	else {
13844567Smarc 	    int i;
13944567Smarc 
14025954Sbloom 	    strcpy(ttyn, dev);
14125954Sbloom 	    strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
14225954Sbloom 	    if (strcmp(argv[0], "+") != 0) {
14318543Sralph 		chown(ttyn, 0, 0);
14444567Smarc 		chmod(ttyn, 0600);
14544567Smarc 		revoke(ttyn);
14625553Smckusick 		/*
14725553Smckusick 		 * Delay the open so DTR stays down long enough to be detected.
14825553Smckusick 		 */
14925553Smckusick 		sleep(2);
15044567Smarc 		while ((i = open(ttyn, O_RDWR)) == -1) {
15118543Sralph 			if (repcnt % 10 == 0) {
15224895Seric 				syslog(LOG_ERR, "%s: %m", ttyn);
15318543Sralph 				closelog();
15418543Sralph 			}
15518543Sralph 			repcnt++;
15618543Sralph 			sleep(60);
15718543Sralph 		}
15844567Smarc 		login_tty(i);
15925954Sbloom 	    }
16018543Sralph 	}
16118543Sralph 
16213795Ssam 	gettable("default", defent, defstrs);
16313795Ssam 	gendefaults();
16413795Ssam 	tname = "default";
16513795Ssam 	if (argc > 1)
16613795Ssam 		tname = argv[1];
16713795Ssam 	for (;;) {
16813795Ssam 		int ldisp = OTTYDISC;
16932209Sbostic 		int off = 0;
17013795Ssam 
17113795Ssam 		gettable(tname, tabent, tabstrs);
17213828Skre 		if (OPset || EPset || APset)
17313828Skre 			APset++, OPset++, EPset++;
17413795Ssam 		setdefaults();
17513795Ssam 		ioctl(0, TIOCFLUSH, 0);		/* clear out the crap */
17632209Sbostic 		ioctl(0, FIONBIO, &off);	/* turn off non-blocking mode */
17746043Sbostic 		ioctl(0, FIOASYNC, &off);	/* ditto for async mode */
17813795Ssam 		if (IS)
17913795Ssam 			tmode.sg_ispeed = speed(IS);
18013795Ssam 		else if (SP)
18113795Ssam 			tmode.sg_ispeed = speed(SP);
18213795Ssam 		if (OS)
18313795Ssam 			tmode.sg_ospeed = speed(OS);
18413795Ssam 		else if (SP)
18513795Ssam 			tmode.sg_ospeed = speed(SP);
18613795Ssam 		tmode.sg_flags = setflags(0);
18713795Ssam 		ioctl(0, TIOCSETP, &tmode);
18813795Ssam 		setchars();
18913795Ssam 		ioctl(0, TIOCSETC, &tc);
19013795Ssam 		if (HC)
19113795Ssam 			ioctl(0, TIOCHPCL, 0);
19218543Sralph 		if (AB) {
19318543Sralph 			extern char *autobaud();
19418543Sralph 
19518543Sralph 			tname = autobaud();
19618543Sralph 			continue;
19718543Sralph 		}
19813795Ssam 		if (PS) {
19913795Ssam 			tname = portselector();
20013795Ssam 			continue;
20113795Ssam 		}
20213795Ssam 		if (CL && *CL)
20313795Ssam 			putpad(CL);
20413795Ssam 		edithost(HE);
20513795Ssam 		if (IM && *IM)
20613795Ssam 			putf(IM);
20713795Ssam 		if (setjmp(timeout)) {
20813795Ssam 			tmode.sg_ispeed = tmode.sg_ospeed = 0;
20913795Ssam 			ioctl(0, TIOCSETP, &tmode);
21013795Ssam 			exit(1);
21113795Ssam 		}
21213795Ssam 		if (TO) {
21313795Ssam 			signal(SIGALRM, dingdong);
21413795Ssam 			alarm(TO);
21513795Ssam 		}
21613795Ssam 		if (getname()) {
21718543Sralph 			register int i;
21818543Sralph 
21918543Sralph 			oflush();
22013795Ssam 			alarm(0);
22113795Ssam 			signal(SIGALRM, SIG_DFL);
22232308Sbostic 			if (name[0] == '-') {
22342459Smarc 				puts("user names may not start with '-'.");
22432308Sbostic 				continue;
22532308Sbostic 			}
22613831Ssam 			if (!(upper || lower || digit))
22713795Ssam 				continue;
22813795Ssam 			allflags = setflags(2);
22913795Ssam 			tmode.sg_flags = allflags & 0xffff;
23013795Ssam 			allflags >>= 16;
23113795Ssam 			if (crmod || NL)
23213795Ssam 				tmode.sg_flags |= CRMOD;
23313795Ssam 			if (upper || UC)
23413795Ssam 				tmode.sg_flags |= LCASE;
23513795Ssam 			if (lower || LC)
23613795Ssam 				tmode.sg_flags &= ~LCASE;
23713795Ssam 			ioctl(0, TIOCSETP, &tmode);
23813795Ssam 			ioctl(0, TIOCSLTC, &ltc);
23913795Ssam 			ioctl(0, TIOCLSET, &allflags);
24013828Skre 			signal(SIGINT, SIG_DFL);
24118543Sralph 			for (i = 0; environ[i] != (char *)0; i++)
24218543Sralph 				env[i] = environ[i];
24318543Sralph 			makeenv(&env[i]);
24444640Smarc 
24544640Smarc 			/*
24644640Smarc 			 * this is what login was doing anyway.
24744640Smarc 			 * soon we rewrite getty completely.
24844640Smarc 			 */
24944640Smarc 			set_ttydefaults(0);
25018543Sralph 			execle(LO, "login", "-p", name, (char *) 0, env);
25132209Sbostic 			syslog(LOG_ERR, "%s: %m", LO);
25213795Ssam 			exit(1);
25313795Ssam 		}
25413795Ssam 		alarm(0);
25513795Ssam 		signal(SIGALRM, SIG_DFL);
25613828Skre 		signal(SIGINT, SIG_IGN);
25713795Ssam 		if (NX && *NX)
25813795Ssam 			tname = NX;
25913795Ssam 	}
26013795Ssam }
26113795Ssam 
26213795Ssam getname()
26313795Ssam {
26446043Sbostic 	register int c;
26513795Ssam 	register char *np;
26613795Ssam 	char cs;
26713795Ssam 
26813828Skre 	/*
26913831Ssam 	 * Interrupt may happen if we use CBREAK mode
27013828Skre 	 */
27113828Skre 	if (setjmp(intrupt)) {
27213828Skre 		signal(SIGINT, SIG_IGN);
27313828Skre 		return (0);
27413828Skre 	}
27513828Skre 	signal(SIGINT, interrupt);
27613795Ssam 	tmode.sg_flags = setflags(0);
27713795Ssam 	ioctl(0, TIOCSETP, &tmode);
27813795Ssam 	tmode.sg_flags = setflags(1);
27913795Ssam 	prompt();
28013885Ssam 	if (PF > 0) {
28114322Ssam 		oflush();
28213885Ssam 		sleep(PF);
28313885Ssam 		PF = 0;
28413885Ssam 	}
28513795Ssam 	ioctl(0, TIOCSETP, &tmode);
28646043Sbostic 	crmod = digit = lower = upper = 0;
28713795Ssam 	np = name;
28813795Ssam 	for (;;) {
28913828Skre 		oflush();
29046043Sbostic 		if (read(STDIN_FILENO, &cs, 1) <= 0)
29113795Ssam 			exit(0);
29213795Ssam 		if ((c = cs&0177) == 0)
29313795Ssam 			return (0);
29413831Ssam 		if (c == EOT)
29513795Ssam 			exit(1);
29618543Sralph 		if (c == '\r' || c == '\n' || np >= &name[sizeof name]) {
29718543Sralph 			putf("\r\n");
29813795Ssam 			break;
29918543Sralph 		}
30042459Smarc 		if (islower(c))
30146043Sbostic 			lower = 1;
30242459Smarc 		else if (isupper(c))
30346043Sbostic 			upper = 1;
30418543Sralph 		else if (c == ERASE || c == '#' || c == '\b') {
30513795Ssam 			if (np > name) {
30613795Ssam 				np--;
30713795Ssam 				if (tmode.sg_ospeed >= B1200)
30813795Ssam 					puts("\b \b");
30913795Ssam 				else
31013795Ssam 					putchr(cs);
31113795Ssam 			}
31213795Ssam 			continue;
31313831Ssam 		} else if (c == KILL || c == '@') {
31413795Ssam 			putchr(cs);
31513795Ssam 			putchr('\r');
31613795Ssam 			if (tmode.sg_ospeed < B1200)
31713795Ssam 				putchr('\n');
31813795Ssam 			/* this is the way they do it down under ... */
31913795Ssam 			else if (np > name)
32013795Ssam 				puts("                                     \r");
32113795Ssam 			prompt();
32213795Ssam 			np = name;
32313795Ssam 			continue;
32442459Smarc 		} else if (isdigit(c))
32513795Ssam 			digit++;
32618543Sralph 		if (IG && (c <= ' ' || c > 0176))
32713795Ssam 			continue;
32813795Ssam 		*np++ = c;
32913795Ssam 		putchr(cs);
33013795Ssam 	}
33113828Skre 	signal(SIGINT, SIG_IGN);
33213795Ssam 	*np = 0;
33313795Ssam 	if (c == '\r')
33446043Sbostic 		crmod = 1;
33513795Ssam 	if (upper && !lower && !LC || UC)
33613795Ssam 		for (np = name; *np; np++)
33713795Ssam 			if (isupper(*np))
33813795Ssam 				*np = tolower(*np);
33913795Ssam 	return (1);
34013795Ssam }
34113795Ssam 
34213795Ssam static
34313795Ssam short	tmspc10[] = {
34413795Ssam 	0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5, 15
34513795Ssam };
34613795Ssam 
34713795Ssam putpad(s)
34813795Ssam 	register char *s;
34913795Ssam {
35013795Ssam 	register pad = 0;
35113795Ssam 	register mspc10;
35213795Ssam 
35313795Ssam 	if (isdigit(*s)) {
35413795Ssam 		while (isdigit(*s)) {
35513795Ssam 			pad *= 10;
35613795Ssam 			pad += *s++ - '0';
35713795Ssam 		}
35813795Ssam 		pad *= 10;
35913795Ssam 		if (*s == '.' && isdigit(s[1])) {
36013795Ssam 			pad += s[1] - '0';
36113795Ssam 			s += 2;
36213795Ssam 		}
36313795Ssam 	}
36413795Ssam 
36513795Ssam 	puts(s);
36613795Ssam 	/*
36713795Ssam 	 * If no delay needed, or output speed is
36813795Ssam 	 * not comprehensible, then don't try to delay.
36913795Ssam 	 */
37013795Ssam 	if (pad == 0)
37113795Ssam 		return;
37213795Ssam 	if (tmode.sg_ospeed <= 0 ||
37313795Ssam 	    tmode.sg_ospeed >= (sizeof tmspc10 / sizeof tmspc10[0]))
37413795Ssam 		return;
37513795Ssam 
37613795Ssam 	/*
37746043Sbostic 	 * Round up by a half a character frame, and then do the delay.
37813795Ssam 	 * Too bad there are no user program accessible programmed delays.
37946043Sbostic 	 * Transmitting pad characters slows many terminals down and also
38046043Sbostic 	 * loads the system.
38113795Ssam 	 */
38213795Ssam 	mspc10 = tmspc10[tmode.sg_ospeed];
38313795Ssam 	pad += mspc10 / 2;
38413795Ssam 	for (pad /= mspc10; pad > 0; pad--)
38513795Ssam 		putchr(*PC);
38613795Ssam }
38713795Ssam 
38813795Ssam puts(s)
38913795Ssam 	register char *s;
39013795Ssam {
39113795Ssam 	while (*s)
39213795Ssam 		putchr(*s++);
39313795Ssam }
39413795Ssam 
39513828Skre char	outbuf[OBUFSIZ];
39613828Skre int	obufcnt = 0;
39713828Skre 
39813795Ssam putchr(cc)
39913795Ssam {
40013795Ssam 	char c;
40113795Ssam 
40213795Ssam 	c = cc;
403*47664Swilliam 	if (!NP) {
404*47664Swilliam 		c |= partab[c&0177] & 0200;
405*47664Swilliam 		if (OP)
406*47664Swilliam 			c ^= 0200;
407*47664Swilliam 	}
40813828Skre 	if (!UB) {
40913828Skre 		outbuf[obufcnt++] = c;
41013828Skre 		if (obufcnt >= OBUFSIZ)
41113828Skre 			oflush();
41213828Skre 	} else
41346043Sbostic 		write(STDOUT_FILENO, &c, 1);
41413795Ssam }
41513795Ssam 
41613828Skre oflush()
41713828Skre {
41813828Skre 	if (obufcnt)
41946043Sbostic 		write(STDOUT_FILENO, outbuf, obufcnt);
42013828Skre 	obufcnt = 0;
42113828Skre }
42213828Skre 
42313795Ssam prompt()
42413795Ssam {
42513795Ssam 
42613795Ssam 	putf(LM);
42713795Ssam 	if (CO)
42813795Ssam 		putchr('\n');
42913795Ssam }
43013795Ssam 
43113795Ssam putf(cp)
43213795Ssam 	register char *cp;
43313795Ssam {
43413795Ssam 	extern char editedhost[];
43546043Sbostic 	time_t t;
43646670Sbostic 	char *slash, db[100];
43713795Ssam 
43813795Ssam 	while (*cp) {
43913795Ssam 		if (*cp != '%') {
44013795Ssam 			putchr(*cp++);
44113795Ssam 			continue;
44213795Ssam 		}
44313795Ssam 		switch (*++cp) {
44413795Ssam 
44518543Sralph 		case 't':
44618543Sralph 			slash = rindex(ttyn, '/');
44718543Sralph 			if (slash == (char *) 0)
44818543Sralph 				puts(ttyn);
44918543Sralph 			else
45018543Sralph 				puts(&slash[1]);
45118543Sralph 			break;
45218543Sralph 
45313795Ssam 		case 'h':
45413795Ssam 			puts(editedhost);
45513795Ssam 			break;
45613795Ssam 
45746670Sbostic 		case 'd': {
45846967Sbostic 			static char fmt[] = "%l:% %P on %A, %d %B %Y";
45946670Sbostic 
46046670Sbostic 			fmt[4] = 'M';		/* I *hate* SCCS... */
46146043Sbostic 			(void)time(&t);
46246670Sbostic 			(void)strftime(db, sizeof(db), fmt, localtime(&t));
46346043Sbostic 			puts(db);
46415713Sralph 			break;
46546670Sbostic 		}
46615713Sralph 
46713795Ssam 		case '%':
46813795Ssam 			putchr('%');
46913795Ssam 			break;
47013795Ssam 		}
47113795Ssam 		cp++;
47213795Ssam 	}
47313795Ssam }
474