xref: /csrg-svn/libexec/getty/main.c (revision 63576)
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*63576Sbostic static char sccsid[] = "@(#)main.c	5.22 (Berkeley) 06/20/93";
1646043Sbostic #endif /* not lint */
1719054Sdist 
1846043Sbostic #define USE_OLD_TTY
1913795Ssam 
2042459Smarc #include <sys/param.h>
2146670Sbostic #include <sys/stat.h>
2261459Smckusick #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 
4061459Smckusick /*
4161459Smckusick  * Set the amount of running time that getty should accumulate
4261459Smckusick  * before deciding that something is wrong and exit.
4361459Smckusick  */
4461459Smckusick #define GETTY_TIMEOUT	60 /* seconds */
4561459Smckusick 
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 
11961459Smckusick /*
12061459Smckusick  * Action to take when getty is running too long.
12161459Smckusick  */
12261459Smckusick void
123*63576Sbostic timeoverrun(signo)
124*63576Sbostic 	int signo;
12561459Smckusick {
12661459Smckusick 
12761459Smckusick 	syslog(LOG_ERR, "getty exiting due to excessive running time\n");
12861459Smckusick 	exit(1);
12961459Smckusick }
13061459Smckusick 
13160091Sbostic static int	getname __P((void));
13260091Sbostic static void	oflush __P((void));
13360091Sbostic static void	prompt __P((void));
13460091Sbostic static void	putchr __P((int));
13560091Sbostic static void	putf __P((char *));
13660091Sbostic static void	putpad __P((char *));
13760091Sbostic static void	puts __P((char *));
13860091Sbostic 
13960091Sbostic int
14013795Ssam main(argc, argv)
14146043Sbostic 	int argc;
14260091Sbostic 	char *argv[];
14313795Ssam {
14460091Sbostic 	extern char **environ;
14513795Ssam 	char *tname;
14613795Ssam 	long allflags;
14718543Sralph 	int repcnt = 0;
14861459Smckusick 	struct rlimit limit;
14913795Ssam 
15013828Skre 	signal(SIGINT, SIG_IGN);
15113795Ssam /*
15213795Ssam 	signal(SIGQUIT, SIG_DFL);
15313795Ssam */
15424890Seric 	openlog("getty", LOG_ODELAY|LOG_CONS, LOG_AUTH);
15513795Ssam 	gethostname(hostname, sizeof(hostname));
15613795Ssam 	if (hostname[0] == '\0')
15713795Ssam 		strcpy(hostname, "Amnesiac");
15861459Smckusick 
15918543Sralph 	/*
16061459Smckusick 	 * Limit running time to deal with broken or dead lines.
16161459Smckusick 	 */
162*63576Sbostic 	(void)signal(SIGXCPU, timeoverrun);
16361459Smckusick 	limit.rlim_max = RLIM_INFINITY;
16461459Smckusick 	limit.rlim_cur = GETTY_TIMEOUT;
165*63576Sbostic 	(void)setrlimit(RLIMIT_CPU, &limit);
16661459Smckusick 
16761459Smckusick 	/*
16818543Sralph 	 * The following is a work around for vhangup interactions
16918543Sralph 	 * which cause great problems getting window systems started.
17018543Sralph 	 * If the tty line is "-", we do the old style getty presuming
17118543Sralph 	 * that the file descriptors are already set up for us.
17218543Sralph 	 * J. Gettys - MIT Project Athena.
17318543Sralph 	 */
17418543Sralph 	if (argc <= 2 || strcmp(argv[2], "-") == 0)
17525954Sbloom 	    strcpy(ttyn, ttyname(0));
17618543Sralph 	else {
17744567Smarc 	    int i;
17844567Smarc 
17925954Sbloom 	    strcpy(ttyn, dev);
18025954Sbloom 	    strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
18125954Sbloom 	    if (strcmp(argv[0], "+") != 0) {
18218543Sralph 		chown(ttyn, 0, 0);
18344567Smarc 		chmod(ttyn, 0600);
18444567Smarc 		revoke(ttyn);
18525553Smckusick 		/*
18625553Smckusick 		 * Delay the open so DTR stays down long enough to be detected.
18725553Smckusick 		 */
18825553Smckusick 		sleep(2);
18944567Smarc 		while ((i = open(ttyn, O_RDWR)) == -1) {
19018543Sralph 			if (repcnt % 10 == 0) {
19124895Seric 				syslog(LOG_ERR, "%s: %m", ttyn);
19218543Sralph 				closelog();
19318543Sralph 			}
19418543Sralph 			repcnt++;
19518543Sralph 			sleep(60);
19618543Sralph 		}
19744567Smarc 		login_tty(i);
19825954Sbloom 	    }
19918543Sralph 	}
20018543Sralph 
20160499Selan 	gettable("default", defent);
20213795Ssam 	gendefaults();
20313795Ssam 	tname = "default";
20413795Ssam 	if (argc > 1)
20513795Ssam 		tname = argv[1];
20613795Ssam 	for (;;) {
20753076Sbostic 		int off;
20813795Ssam 
20960499Selan 		gettable(tname, tabent);
21013828Skre 		if (OPset || EPset || APset)
21113828Skre 			APset++, OPset++, EPset++;
21213795Ssam 		setdefaults();
21353076Sbostic 		off = 0;
21453076Sbostic 		ioctl(0, TIOCFLUSH, &off);	/* clear out the crap */
21532209Sbostic 		ioctl(0, FIONBIO, &off);	/* turn off non-blocking mode */
21646043Sbostic 		ioctl(0, FIOASYNC, &off);	/* ditto for async mode */
21713795Ssam 		if (IS)
21813795Ssam 			tmode.sg_ispeed = speed(IS);
21913795Ssam 		else if (SP)
22013795Ssam 			tmode.sg_ispeed = speed(SP);
22113795Ssam 		if (OS)
22213795Ssam 			tmode.sg_ospeed = speed(OS);
22313795Ssam 		else if (SP)
22413795Ssam 			tmode.sg_ospeed = speed(SP);
22513795Ssam 		tmode.sg_flags = setflags(0);
22613795Ssam 		ioctl(0, TIOCSETP, &tmode);
22713795Ssam 		setchars();
22813795Ssam 		ioctl(0, TIOCSETC, &tc);
22913795Ssam 		if (HC)
23013795Ssam 			ioctl(0, TIOCHPCL, 0);
23118543Sralph 		if (AB) {
23218543Sralph 			extern char *autobaud();
23318543Sralph 
23418543Sralph 			tname = autobaud();
23518543Sralph 			continue;
23618543Sralph 		}
23713795Ssam 		if (PS) {
23813795Ssam 			tname = portselector();
23913795Ssam 			continue;
24013795Ssam 		}
24113795Ssam 		if (CL && *CL)
24213795Ssam 			putpad(CL);
24313795Ssam 		edithost(HE);
24413795Ssam 		if (IM && *IM)
24513795Ssam 			putf(IM);
24613795Ssam 		if (setjmp(timeout)) {
24713795Ssam 			tmode.sg_ispeed = tmode.sg_ospeed = 0;
24813795Ssam 			ioctl(0, TIOCSETP, &tmode);
24913795Ssam 			exit(1);
25013795Ssam 		}
25113795Ssam 		if (TO) {
25213795Ssam 			signal(SIGALRM, dingdong);
25313795Ssam 			alarm(TO);
25413795Ssam 		}
25513795Ssam 		if (getname()) {
25618543Sralph 			register int i;
25718543Sralph 
25818543Sralph 			oflush();
25913795Ssam 			alarm(0);
26013795Ssam 			signal(SIGALRM, SIG_DFL);
26132308Sbostic 			if (name[0] == '-') {
26242459Smarc 				puts("user names may not start with '-'.");
26332308Sbostic 				continue;
26432308Sbostic 			}
26513831Ssam 			if (!(upper || lower || digit))
26613795Ssam 				continue;
26713795Ssam 			allflags = setflags(2);
26813795Ssam 			tmode.sg_flags = allflags & 0xffff;
26913795Ssam 			allflags >>= 16;
27013795Ssam 			if (crmod || NL)
27113795Ssam 				tmode.sg_flags |= CRMOD;
27213795Ssam 			if (upper || UC)
27313795Ssam 				tmode.sg_flags |= LCASE;
27413795Ssam 			if (lower || LC)
27513795Ssam 				tmode.sg_flags &= ~LCASE;
27613795Ssam 			ioctl(0, TIOCSETP, &tmode);
27713795Ssam 			ioctl(0, TIOCSLTC, &ltc);
27813795Ssam 			ioctl(0, TIOCLSET, &allflags);
27913828Skre 			signal(SIGINT, SIG_DFL);
28018543Sralph 			for (i = 0; environ[i] != (char *)0; i++)
28118543Sralph 				env[i] = environ[i];
28218543Sralph 			makeenv(&env[i]);
28344640Smarc 
28444640Smarc 			/*
28544640Smarc 			 * this is what login was doing anyway.
28644640Smarc 			 * soon we rewrite getty completely.
28744640Smarc 			 */
28844640Smarc 			set_ttydefaults(0);
289*63576Sbostic 			limit.rlim_max = RLIM_INFINITY;
290*63576Sbostic 			limit.rlim_cur = RLIM_INFINITY;
291*63576Sbostic 			(void)setrlimit(RLIMIT_CPU, &limit);
29218543Sralph 			execle(LO, "login", "-p", name, (char *) 0, env);
29332209Sbostic 			syslog(LOG_ERR, "%s: %m", LO);
29413795Ssam 			exit(1);
29513795Ssam 		}
29613795Ssam 		alarm(0);
29713795Ssam 		signal(SIGALRM, SIG_DFL);
29813828Skre 		signal(SIGINT, SIG_IGN);
29913795Ssam 		if (NX && *NX)
30013795Ssam 			tname = NX;
30113795Ssam 	}
30213795Ssam }
30313795Ssam 
30460091Sbostic static int
30513795Ssam getname()
30613795Ssam {
30746043Sbostic 	register int c;
30813795Ssam 	register char *np;
30913795Ssam 	char cs;
31013795Ssam 
31113828Skre 	/*
31213831Ssam 	 * Interrupt may happen if we use CBREAK mode
31313828Skre 	 */
31413828Skre 	if (setjmp(intrupt)) {
31513828Skre 		signal(SIGINT, SIG_IGN);
31613828Skre 		return (0);
31713828Skre 	}
31813828Skre 	signal(SIGINT, interrupt);
31913795Ssam 	tmode.sg_flags = setflags(0);
32013795Ssam 	ioctl(0, TIOCSETP, &tmode);
32113795Ssam 	tmode.sg_flags = setflags(1);
32213795Ssam 	prompt();
32313885Ssam 	if (PF > 0) {
32414322Ssam 		oflush();
32513885Ssam 		sleep(PF);
32613885Ssam 		PF = 0;
32713885Ssam 	}
32813795Ssam 	ioctl(0, TIOCSETP, &tmode);
32946043Sbostic 	crmod = digit = lower = upper = 0;
33013795Ssam 	np = name;
33113795Ssam 	for (;;) {
33213828Skre 		oflush();
33346043Sbostic 		if (read(STDIN_FILENO, &cs, 1) <= 0)
33413795Ssam 			exit(0);
33513795Ssam 		if ((c = cs&0177) == 0)
33613795Ssam 			return (0);
33713831Ssam 		if (c == EOT)
33813795Ssam 			exit(1);
33918543Sralph 		if (c == '\r' || c == '\n' || np >= &name[sizeof name]) {
34018543Sralph 			putf("\r\n");
34113795Ssam 			break;
34218543Sralph 		}
34342459Smarc 		if (islower(c))
34446043Sbostic 			lower = 1;
34542459Smarc 		else if (isupper(c))
34646043Sbostic 			upper = 1;
34718543Sralph 		else if (c == ERASE || c == '#' || c == '\b') {
34813795Ssam 			if (np > name) {
34913795Ssam 				np--;
35013795Ssam 				if (tmode.sg_ospeed >= B1200)
35113795Ssam 					puts("\b \b");
35213795Ssam 				else
35313795Ssam 					putchr(cs);
35413795Ssam 			}
35513795Ssam 			continue;
35613831Ssam 		} else if (c == KILL || c == '@') {
35713795Ssam 			putchr(cs);
35813795Ssam 			putchr('\r');
35913795Ssam 			if (tmode.sg_ospeed < B1200)
36013795Ssam 				putchr('\n');
36113795Ssam 			/* this is the way they do it down under ... */
36213795Ssam 			else if (np > name)
36313795Ssam 				puts("                                     \r");
36413795Ssam 			prompt();
36513795Ssam 			np = name;
36613795Ssam 			continue;
36742459Smarc 		} else if (isdigit(c))
36813795Ssam 			digit++;
36918543Sralph 		if (IG && (c <= ' ' || c > 0176))
37013795Ssam 			continue;
37113795Ssam 		*np++ = c;
37213795Ssam 		putchr(cs);
37313795Ssam 	}
37413828Skre 	signal(SIGINT, SIG_IGN);
37513795Ssam 	*np = 0;
37613795Ssam 	if (c == '\r')
37746043Sbostic 		crmod = 1;
37813795Ssam 	if (upper && !lower && !LC || UC)
37913795Ssam 		for (np = name; *np; np++)
38013795Ssam 			if (isupper(*np))
38113795Ssam 				*np = tolower(*np);
38213795Ssam 	return (1);
38313795Ssam }
38413795Ssam 
38513795Ssam static
38613795Ssam short	tmspc10[] = {
38713795Ssam 	0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5, 15
38813795Ssam };
38913795Ssam 
39060091Sbostic static void
39113795Ssam putpad(s)
39213795Ssam 	register char *s;
39313795Ssam {
39413795Ssam 	register pad = 0;
39513795Ssam 	register mspc10;
39613795Ssam 
39713795Ssam 	if (isdigit(*s)) {
39813795Ssam 		while (isdigit(*s)) {
39913795Ssam 			pad *= 10;
40013795Ssam 			pad += *s++ - '0';
40113795Ssam 		}
40213795Ssam 		pad *= 10;
40313795Ssam 		if (*s == '.' && isdigit(s[1])) {
40413795Ssam 			pad += s[1] - '0';
40513795Ssam 			s += 2;
40613795Ssam 		}
40713795Ssam 	}
40813795Ssam 
40913795Ssam 	puts(s);
41013795Ssam 	/*
41113795Ssam 	 * If no delay needed, or output speed is
41213795Ssam 	 * not comprehensible, then don't try to delay.
41313795Ssam 	 */
41413795Ssam 	if (pad == 0)
41513795Ssam 		return;
41613795Ssam 	if (tmode.sg_ospeed <= 0 ||
41713795Ssam 	    tmode.sg_ospeed >= (sizeof tmspc10 / sizeof tmspc10[0]))
41813795Ssam 		return;
41913795Ssam 
42013795Ssam 	/*
42146043Sbostic 	 * Round up by a half a character frame, and then do the delay.
42213795Ssam 	 * Too bad there are no user program accessible programmed delays.
42346043Sbostic 	 * Transmitting pad characters slows many terminals down and also
42446043Sbostic 	 * loads the system.
42513795Ssam 	 */
42613795Ssam 	mspc10 = tmspc10[tmode.sg_ospeed];
42713795Ssam 	pad += mspc10 / 2;
42813795Ssam 	for (pad /= mspc10; pad > 0; pad--)
42913795Ssam 		putchr(*PC);
43013795Ssam }
43113795Ssam 
43260091Sbostic static void
43313795Ssam puts(s)
43413795Ssam 	register char *s;
43513795Ssam {
43613795Ssam 	while (*s)
43713795Ssam 		putchr(*s++);
43813795Ssam }
43913795Ssam 
44013828Skre char	outbuf[OBUFSIZ];
44113828Skre int	obufcnt = 0;
44213828Skre 
44360091Sbostic static void
44413795Ssam putchr(cc)
44560091Sbostic 	int cc;
44613795Ssam {
44713795Ssam 	char c;
44813795Ssam 
44913795Ssam 	c = cc;
45047664Swilliam 	if (!NP) {
45147664Swilliam 		c |= partab[c&0177] & 0200;
45247664Swilliam 		if (OP)
45347664Swilliam 			c ^= 0200;
45447664Swilliam 	}
45513828Skre 	if (!UB) {
45613828Skre 		outbuf[obufcnt++] = c;
45713828Skre 		if (obufcnt >= OBUFSIZ)
45813828Skre 			oflush();
45913828Skre 	} else
46046043Sbostic 		write(STDOUT_FILENO, &c, 1);
46113795Ssam }
46213795Ssam 
46360091Sbostic static void
46413828Skre oflush()
46513828Skre {
46613828Skre 	if (obufcnt)
46746043Sbostic 		write(STDOUT_FILENO, outbuf, obufcnt);
46813828Skre 	obufcnt = 0;
46913828Skre }
47013828Skre 
47160091Sbostic static void
47213795Ssam prompt()
47313795Ssam {
47413795Ssam 
47513795Ssam 	putf(LM);
47613795Ssam 	if (CO)
47713795Ssam 		putchr('\n');
47813795Ssam }
47913795Ssam 
48060091Sbostic static void
48113795Ssam putf(cp)
48213795Ssam 	register char *cp;
48313795Ssam {
48413795Ssam 	extern char editedhost[];
48546043Sbostic 	time_t t;
48646670Sbostic 	char *slash, db[100];
48713795Ssam 
48813795Ssam 	while (*cp) {
48913795Ssam 		if (*cp != '%') {
49013795Ssam 			putchr(*cp++);
49113795Ssam 			continue;
49213795Ssam 		}
49313795Ssam 		switch (*++cp) {
49413795Ssam 
49518543Sralph 		case 't':
49660091Sbostic 			slash = strrchr(ttyn, '/');
49718543Sralph 			if (slash == (char *) 0)
49818543Sralph 				puts(ttyn);
49918543Sralph 			else
50018543Sralph 				puts(&slash[1]);
50118543Sralph 			break;
50218543Sralph 
50313795Ssam 		case 'h':
50413795Ssam 			puts(editedhost);
50513795Ssam 			break;
50613795Ssam 
50746670Sbostic 		case 'd': {
50846967Sbostic 			static char fmt[] = "%l:% %P on %A, %d %B %Y";
50946670Sbostic 
51046670Sbostic 			fmt[4] = 'M';		/* I *hate* SCCS... */
51146043Sbostic 			(void)time(&t);
51246670Sbostic 			(void)strftime(db, sizeof(db), fmt, localtime(&t));
51346043Sbostic 			puts(db);
51415713Sralph 			break;
51546670Sbostic 		}
51615713Sralph 
51713795Ssam 		case '%':
51813795Ssam 			putchr('%');
51913795Ssam 			break;
52013795Ssam 		}
52113795Ssam 		cp++;
52213795Ssam 	}
52313795Ssam }
524