xref: /csrg-svn/libexec/getty/main.c (revision 61459)
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*61459Smckusick static char sccsid[] = "@(#)main.c	5.21 (Berkeley) 06/04/93";
1646043Sbostic #endif /* not lint */
1719054Sdist 
1846043Sbostic #define USE_OLD_TTY
1913795Ssam 
2042459Smarc #include <sys/param.h>
2146670Sbostic #include <sys/stat.h>
22*61459Smckusick #include <sys/resource.h>
2360091Sbostic 
2460091Sbostic #include <ctype.h>
2560091Sbostic #include <ctype.h>
2646670Sbostic #include <fcntl.h>
2760091Sbostic #include <setjmp.h>
2813795Ssam #include <sgtty.h>
2960091Sbostic #include <signal.h>
3060091Sbostic #include <stdlib.h>
3160091Sbostic #include <string.h>
3260091Sbostic #include <syslog.h>
3346670Sbostic #include <time.h>
3446043Sbostic #include <unistd.h>
3560091Sbostic 
3613795Ssam #include "gettytab.h"
3742459Smarc #include "pathnames.h"
3860091Sbostic #include "extern.h"
3913795Ssam 
40*61459Smckusick /*
41*61459Smckusick  * Set the amount of running time that getty should accumulate
42*61459Smckusick  * before deciding that something is wrong and exit.
43*61459Smckusick  */
44*61459Smckusick #define GETTY_TIMEOUT	60 /* seconds */
45*61459Smckusick 
4613795Ssam struct	sgttyb tmode = {
4713795Ssam 	0, 0, CERASE, CKILL, 0
4813795Ssam };
4913795Ssam struct	tchars tc = {
5013795Ssam 	CINTR, CQUIT, CSTART,
5113795Ssam 	CSTOP, CEOF, CBRK,
5213795Ssam };
5313795Ssam struct	ltchars ltc = {
5413795Ssam 	CSUSP, CDSUSP, CRPRNT,
5513795Ssam 	CFLUSH, CWERASE, CLNEXT
5613795Ssam };
5713795Ssam 
5846043Sbostic int crmod, digit, lower, upper;
5913795Ssam 
6042459Smarc char	hostname[MAXHOSTNAMELEN];
6113795Ssam char	name[16];
6242459Smarc char	dev[] = _PATH_DEV;
6318543Sralph char	ttyn[32];
6413795Ssam char	*portselector();
6518543Sralph char	*ttyname();
6613795Ssam 
6713828Skre #define	OBUFSIZ		128
6813795Ssam #define	TABBUFSIZ	512
6913795Ssam 
7013795Ssam char	defent[TABBUFSIZ];
7113795Ssam char	tabent[TABBUFSIZ];
7213795Ssam 
7313795Ssam char	*env[128];
7413795Ssam 
7513795Ssam char partab[] = {
7613795Ssam 	0001,0201,0201,0001,0201,0001,0001,0201,
7713795Ssam 	0202,0004,0003,0205,0005,0206,0201,0001,
7813795Ssam 	0201,0001,0001,0201,0001,0201,0201,0001,
7913795Ssam 	0001,0201,0201,0001,0201,0001,0001,0201,
8013795Ssam 	0200,0000,0000,0200,0000,0200,0200,0000,
8113795Ssam 	0000,0200,0200,0000,0200,0000,0000,0200,
8213795Ssam 	0000,0200,0200,0000,0200,0000,0000,0200,
8313795Ssam 	0200,0000,0000,0200,0000,0200,0200,0000,
8413795Ssam 	0200,0000,0000,0200,0000,0200,0200,0000,
8513795Ssam 	0000,0200,0200,0000,0200,0000,0000,0200,
8613795Ssam 	0000,0200,0200,0000,0200,0000,0000,0200,
8713795Ssam 	0200,0000,0000,0200,0000,0200,0200,0000,
8813795Ssam 	0000,0200,0200,0000,0200,0000,0000,0200,
8913795Ssam 	0200,0000,0000,0200,0000,0200,0200,0000,
9013795Ssam 	0200,0000,0000,0200,0000,0200,0200,0000,
9113795Ssam 	0000,0200,0200,0000,0200,0000,0000,0201
9213795Ssam };
9313795Ssam 
9413795Ssam #define	ERASE	tmode.sg_erase
9513795Ssam #define	KILL	tmode.sg_kill
9613795Ssam #define	EOT	tc.t_eofc
9713795Ssam 
9813795Ssam jmp_buf timeout;
9913795Ssam 
10046670Sbostic static void
10113795Ssam dingdong()
10213795Ssam {
10313795Ssam 
10413795Ssam 	alarm(0);
10513795Ssam 	signal(SIGALRM, SIG_DFL);
10613795Ssam 	longjmp(timeout, 1);
10713795Ssam }
10813795Ssam 
10913828Skre jmp_buf	intrupt;
11013828Skre 
11146670Sbostic static void
11213828Skre interrupt()
11313828Skre {
11413828Skre 
11513828Skre 	signal(SIGINT, interrupt);
11613828Skre 	longjmp(intrupt, 1);
11713828Skre }
11813828Skre 
119*61459Smckusick /*
120*61459Smckusick  * Action to take when getty is running too long.
121*61459Smckusick  */
122*61459Smckusick void
123*61459Smckusick timeoverrun()
124*61459Smckusick {
125*61459Smckusick 
126*61459Smckusick 	syslog(LOG_ERR, "getty exiting due to excessive running time\n");
127*61459Smckusick 	exit(1);
128*61459Smckusick }
129*61459Smckusick 
13060091Sbostic static int	getname __P((void));
13160091Sbostic static void	oflush __P((void));
13260091Sbostic static void	prompt __P((void));
13360091Sbostic static void	putchr __P((int));
13460091Sbostic static void	putf __P((char *));
13560091Sbostic static void	putpad __P((char *));
13660091Sbostic static void	puts __P((char *));
13760091Sbostic 
13860091Sbostic int
13913795Ssam main(argc, argv)
14046043Sbostic 	int argc;
14160091Sbostic 	char *argv[];
14213795Ssam {
14360091Sbostic 	extern char **environ;
14413795Ssam 	char *tname;
14513795Ssam 	long allflags;
14618543Sralph 	int repcnt = 0;
147*61459Smckusick 	struct rlimit limit;
14813795Ssam 
14913828Skre 	signal(SIGINT, SIG_IGN);
15013795Ssam /*
15113795Ssam 	signal(SIGQUIT, SIG_DFL);
15213795Ssam */
15324890Seric 	openlog("getty", LOG_ODELAY|LOG_CONS, LOG_AUTH);
15413795Ssam 	gethostname(hostname, sizeof(hostname));
15513795Ssam 	if (hostname[0] == '\0')
15613795Ssam 		strcpy(hostname, "Amnesiac");
157*61459Smckusick 
15818543Sralph 	/*
159*61459Smckusick 	 * Limit running time to deal with broken or dead lines.
160*61459Smckusick 	 */
161*61459Smckusick 	signal(SIGXCPU, timeoverrun);
162*61459Smckusick 	limit.rlim_max = RLIM_INFINITY;
163*61459Smckusick 	limit.rlim_cur = GETTY_TIMEOUT;
164*61459Smckusick 	setrlimit(RLIMIT_CPU, &limit);
165*61459Smckusick 
166*61459Smckusick 	/*
16718543Sralph 	 * The following is a work around for vhangup interactions
16818543Sralph 	 * which cause great problems getting window systems started.
16918543Sralph 	 * If the tty line is "-", we do the old style getty presuming
17018543Sralph 	 * that the file descriptors are already set up for us.
17118543Sralph 	 * J. Gettys - MIT Project Athena.
17218543Sralph 	 */
17318543Sralph 	if (argc <= 2 || strcmp(argv[2], "-") == 0)
17425954Sbloom 	    strcpy(ttyn, ttyname(0));
17518543Sralph 	else {
17644567Smarc 	    int i;
17744567Smarc 
17825954Sbloom 	    strcpy(ttyn, dev);
17925954Sbloom 	    strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
18025954Sbloom 	    if (strcmp(argv[0], "+") != 0) {
18118543Sralph 		chown(ttyn, 0, 0);
18244567Smarc 		chmod(ttyn, 0600);
18344567Smarc 		revoke(ttyn);
18425553Smckusick 		/*
18525553Smckusick 		 * Delay the open so DTR stays down long enough to be detected.
18625553Smckusick 		 */
18725553Smckusick 		sleep(2);
18844567Smarc 		while ((i = open(ttyn, O_RDWR)) == -1) {
18918543Sralph 			if (repcnt % 10 == 0) {
19024895Seric 				syslog(LOG_ERR, "%s: %m", ttyn);
19118543Sralph 				closelog();
19218543Sralph 			}
19318543Sralph 			repcnt++;
19418543Sralph 			sleep(60);
19518543Sralph 		}
19644567Smarc 		login_tty(i);
19725954Sbloom 	    }
19818543Sralph 	}
19918543Sralph 
20060499Selan 	gettable("default", defent);
20113795Ssam 	gendefaults();
20213795Ssam 	tname = "default";
20313795Ssam 	if (argc > 1)
20413795Ssam 		tname = argv[1];
20513795Ssam 	for (;;) {
20653076Sbostic 		int off;
20713795Ssam 
20860499Selan 		gettable(tname, tabent);
20913828Skre 		if (OPset || EPset || APset)
21013828Skre 			APset++, OPset++, EPset++;
21113795Ssam 		setdefaults();
21253076Sbostic 		off = 0;
21353076Sbostic 		ioctl(0, TIOCFLUSH, &off);	/* clear out the crap */
21432209Sbostic 		ioctl(0, FIONBIO, &off);	/* turn off non-blocking mode */
21546043Sbostic 		ioctl(0, FIOASYNC, &off);	/* ditto for async mode */
21613795Ssam 		if (IS)
21713795Ssam 			tmode.sg_ispeed = speed(IS);
21813795Ssam 		else if (SP)
21913795Ssam 			tmode.sg_ispeed = speed(SP);
22013795Ssam 		if (OS)
22113795Ssam 			tmode.sg_ospeed = speed(OS);
22213795Ssam 		else if (SP)
22313795Ssam 			tmode.sg_ospeed = speed(SP);
22413795Ssam 		tmode.sg_flags = setflags(0);
22513795Ssam 		ioctl(0, TIOCSETP, &tmode);
22613795Ssam 		setchars();
22713795Ssam 		ioctl(0, TIOCSETC, &tc);
22813795Ssam 		if (HC)
22913795Ssam 			ioctl(0, TIOCHPCL, 0);
23018543Sralph 		if (AB) {
23118543Sralph 			extern char *autobaud();
23218543Sralph 
23318543Sralph 			tname = autobaud();
23418543Sralph 			continue;
23518543Sralph 		}
23613795Ssam 		if (PS) {
23713795Ssam 			tname = portselector();
23813795Ssam 			continue;
23913795Ssam 		}
24013795Ssam 		if (CL && *CL)
24113795Ssam 			putpad(CL);
24213795Ssam 		edithost(HE);
24313795Ssam 		if (IM && *IM)
24413795Ssam 			putf(IM);
24513795Ssam 		if (setjmp(timeout)) {
24613795Ssam 			tmode.sg_ispeed = tmode.sg_ospeed = 0;
24713795Ssam 			ioctl(0, TIOCSETP, &tmode);
24813795Ssam 			exit(1);
24913795Ssam 		}
25013795Ssam 		if (TO) {
25113795Ssam 			signal(SIGALRM, dingdong);
25213795Ssam 			alarm(TO);
25313795Ssam 		}
25413795Ssam 		if (getname()) {
25518543Sralph 			register int i;
25618543Sralph 
25718543Sralph 			oflush();
25813795Ssam 			alarm(0);
25913795Ssam 			signal(SIGALRM, SIG_DFL);
26032308Sbostic 			if (name[0] == '-') {
26142459Smarc 				puts("user names may not start with '-'.");
26232308Sbostic 				continue;
26332308Sbostic 			}
26413831Ssam 			if (!(upper || lower || digit))
26513795Ssam 				continue;
26613795Ssam 			allflags = setflags(2);
26713795Ssam 			tmode.sg_flags = allflags & 0xffff;
26813795Ssam 			allflags >>= 16;
26913795Ssam 			if (crmod || NL)
27013795Ssam 				tmode.sg_flags |= CRMOD;
27113795Ssam 			if (upper || UC)
27213795Ssam 				tmode.sg_flags |= LCASE;
27313795Ssam 			if (lower || LC)
27413795Ssam 				tmode.sg_flags &= ~LCASE;
27513795Ssam 			ioctl(0, TIOCSETP, &tmode);
27613795Ssam 			ioctl(0, TIOCSLTC, &ltc);
27713795Ssam 			ioctl(0, TIOCLSET, &allflags);
27813828Skre 			signal(SIGINT, SIG_DFL);
27918543Sralph 			for (i = 0; environ[i] != (char *)0; i++)
28018543Sralph 				env[i] = environ[i];
28118543Sralph 			makeenv(&env[i]);
28244640Smarc 
28344640Smarc 			/*
28444640Smarc 			 * this is what login was doing anyway.
28544640Smarc 			 * soon we rewrite getty completely.
28644640Smarc 			 */
28744640Smarc 			set_ttydefaults(0);
28818543Sralph 			execle(LO, "login", "-p", name, (char *) 0, env);
28932209Sbostic 			syslog(LOG_ERR, "%s: %m", LO);
29013795Ssam 			exit(1);
29113795Ssam 		}
29213795Ssam 		alarm(0);
29313795Ssam 		signal(SIGALRM, SIG_DFL);
29413828Skre 		signal(SIGINT, SIG_IGN);
29513795Ssam 		if (NX && *NX)
29613795Ssam 			tname = NX;
29713795Ssam 	}
29813795Ssam }
29913795Ssam 
30060091Sbostic static int
30113795Ssam getname()
30213795Ssam {
30346043Sbostic 	register int c;
30413795Ssam 	register char *np;
30513795Ssam 	char cs;
30613795Ssam 
30713828Skre 	/*
30813831Ssam 	 * Interrupt may happen if we use CBREAK mode
30913828Skre 	 */
31013828Skre 	if (setjmp(intrupt)) {
31113828Skre 		signal(SIGINT, SIG_IGN);
31213828Skre 		return (0);
31313828Skre 	}
31413828Skre 	signal(SIGINT, interrupt);
31513795Ssam 	tmode.sg_flags = setflags(0);
31613795Ssam 	ioctl(0, TIOCSETP, &tmode);
31713795Ssam 	tmode.sg_flags = setflags(1);
31813795Ssam 	prompt();
31913885Ssam 	if (PF > 0) {
32014322Ssam 		oflush();
32113885Ssam 		sleep(PF);
32213885Ssam 		PF = 0;
32313885Ssam 	}
32413795Ssam 	ioctl(0, TIOCSETP, &tmode);
32546043Sbostic 	crmod = digit = lower = upper = 0;
32613795Ssam 	np = name;
32713795Ssam 	for (;;) {
32813828Skre 		oflush();
32946043Sbostic 		if (read(STDIN_FILENO, &cs, 1) <= 0)
33013795Ssam 			exit(0);
33113795Ssam 		if ((c = cs&0177) == 0)
33213795Ssam 			return (0);
33313831Ssam 		if (c == EOT)
33413795Ssam 			exit(1);
33518543Sralph 		if (c == '\r' || c == '\n' || np >= &name[sizeof name]) {
33618543Sralph 			putf("\r\n");
33713795Ssam 			break;
33818543Sralph 		}
33942459Smarc 		if (islower(c))
34046043Sbostic 			lower = 1;
34142459Smarc 		else if (isupper(c))
34246043Sbostic 			upper = 1;
34318543Sralph 		else if (c == ERASE || c == '#' || c == '\b') {
34413795Ssam 			if (np > name) {
34513795Ssam 				np--;
34613795Ssam 				if (tmode.sg_ospeed >= B1200)
34713795Ssam 					puts("\b \b");
34813795Ssam 				else
34913795Ssam 					putchr(cs);
35013795Ssam 			}
35113795Ssam 			continue;
35213831Ssam 		} else if (c == KILL || c == '@') {
35313795Ssam 			putchr(cs);
35413795Ssam 			putchr('\r');
35513795Ssam 			if (tmode.sg_ospeed < B1200)
35613795Ssam 				putchr('\n');
35713795Ssam 			/* this is the way they do it down under ... */
35813795Ssam 			else if (np > name)
35913795Ssam 				puts("                                     \r");
36013795Ssam 			prompt();
36113795Ssam 			np = name;
36213795Ssam 			continue;
36342459Smarc 		} else if (isdigit(c))
36413795Ssam 			digit++;
36518543Sralph 		if (IG && (c <= ' ' || c > 0176))
36613795Ssam 			continue;
36713795Ssam 		*np++ = c;
36813795Ssam 		putchr(cs);
36913795Ssam 	}
37013828Skre 	signal(SIGINT, SIG_IGN);
37113795Ssam 	*np = 0;
37213795Ssam 	if (c == '\r')
37346043Sbostic 		crmod = 1;
37413795Ssam 	if (upper && !lower && !LC || UC)
37513795Ssam 		for (np = name; *np; np++)
37613795Ssam 			if (isupper(*np))
37713795Ssam 				*np = tolower(*np);
37813795Ssam 	return (1);
37913795Ssam }
38013795Ssam 
38113795Ssam static
38213795Ssam short	tmspc10[] = {
38313795Ssam 	0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5, 15
38413795Ssam };
38513795Ssam 
38660091Sbostic static void
38713795Ssam putpad(s)
38813795Ssam 	register char *s;
38913795Ssam {
39013795Ssam 	register pad = 0;
39113795Ssam 	register mspc10;
39213795Ssam 
39313795Ssam 	if (isdigit(*s)) {
39413795Ssam 		while (isdigit(*s)) {
39513795Ssam 			pad *= 10;
39613795Ssam 			pad += *s++ - '0';
39713795Ssam 		}
39813795Ssam 		pad *= 10;
39913795Ssam 		if (*s == '.' && isdigit(s[1])) {
40013795Ssam 			pad += s[1] - '0';
40113795Ssam 			s += 2;
40213795Ssam 		}
40313795Ssam 	}
40413795Ssam 
40513795Ssam 	puts(s);
40613795Ssam 	/*
40713795Ssam 	 * If no delay needed, or output speed is
40813795Ssam 	 * not comprehensible, then don't try to delay.
40913795Ssam 	 */
41013795Ssam 	if (pad == 0)
41113795Ssam 		return;
41213795Ssam 	if (tmode.sg_ospeed <= 0 ||
41313795Ssam 	    tmode.sg_ospeed >= (sizeof tmspc10 / sizeof tmspc10[0]))
41413795Ssam 		return;
41513795Ssam 
41613795Ssam 	/*
41746043Sbostic 	 * Round up by a half a character frame, and then do the delay.
41813795Ssam 	 * Too bad there are no user program accessible programmed delays.
41946043Sbostic 	 * Transmitting pad characters slows many terminals down and also
42046043Sbostic 	 * loads the system.
42113795Ssam 	 */
42213795Ssam 	mspc10 = tmspc10[tmode.sg_ospeed];
42313795Ssam 	pad += mspc10 / 2;
42413795Ssam 	for (pad /= mspc10; pad > 0; pad--)
42513795Ssam 		putchr(*PC);
42613795Ssam }
42713795Ssam 
42860091Sbostic static void
42913795Ssam puts(s)
43013795Ssam 	register char *s;
43113795Ssam {
43213795Ssam 	while (*s)
43313795Ssam 		putchr(*s++);
43413795Ssam }
43513795Ssam 
43613828Skre char	outbuf[OBUFSIZ];
43713828Skre int	obufcnt = 0;
43813828Skre 
43960091Sbostic static void
44013795Ssam putchr(cc)
44160091Sbostic 	int cc;
44213795Ssam {
44313795Ssam 	char c;
44413795Ssam 
44513795Ssam 	c = cc;
44647664Swilliam 	if (!NP) {
44747664Swilliam 		c |= partab[c&0177] & 0200;
44847664Swilliam 		if (OP)
44947664Swilliam 			c ^= 0200;
45047664Swilliam 	}
45113828Skre 	if (!UB) {
45213828Skre 		outbuf[obufcnt++] = c;
45313828Skre 		if (obufcnt >= OBUFSIZ)
45413828Skre 			oflush();
45513828Skre 	} else
45646043Sbostic 		write(STDOUT_FILENO, &c, 1);
45713795Ssam }
45813795Ssam 
45960091Sbostic static void
46013828Skre oflush()
46113828Skre {
46213828Skre 	if (obufcnt)
46346043Sbostic 		write(STDOUT_FILENO, outbuf, obufcnt);
46413828Skre 	obufcnt = 0;
46513828Skre }
46613828Skre 
46760091Sbostic static void
46813795Ssam prompt()
46913795Ssam {
47013795Ssam 
47113795Ssam 	putf(LM);
47213795Ssam 	if (CO)
47313795Ssam 		putchr('\n');
47413795Ssam }
47513795Ssam 
47660091Sbostic static void
47713795Ssam putf(cp)
47813795Ssam 	register char *cp;
47913795Ssam {
48013795Ssam 	extern char editedhost[];
48146043Sbostic 	time_t t;
48246670Sbostic 	char *slash, db[100];
48313795Ssam 
48413795Ssam 	while (*cp) {
48513795Ssam 		if (*cp != '%') {
48613795Ssam 			putchr(*cp++);
48713795Ssam 			continue;
48813795Ssam 		}
48913795Ssam 		switch (*++cp) {
49013795Ssam 
49118543Sralph 		case 't':
49260091Sbostic 			slash = strrchr(ttyn, '/');
49318543Sralph 			if (slash == (char *) 0)
49418543Sralph 				puts(ttyn);
49518543Sralph 			else
49618543Sralph 				puts(&slash[1]);
49718543Sralph 			break;
49818543Sralph 
49913795Ssam 		case 'h':
50013795Ssam 			puts(editedhost);
50113795Ssam 			break;
50213795Ssam 
50346670Sbostic 		case 'd': {
50446967Sbostic 			static char fmt[] = "%l:% %P on %A, %d %B %Y";
50546670Sbostic 
50646670Sbostic 			fmt[4] = 'M';		/* I *hate* SCCS... */
50746043Sbostic 			(void)time(&t);
50846670Sbostic 			(void)strftime(db, sizeof(db), fmt, localtime(&t));
50946043Sbostic 			puts(db);
51015713Sralph 			break;
51146670Sbostic 		}
51215713Sralph 
51313795Ssam 		case '%':
51413795Ssam 			putchr('%');
51513795Ssam 			break;
51613795Ssam 		}
51713795Ssam 		cp++;
51813795Ssam 	}
51913795Ssam }
520