main.c revision 1592
1/*-
2 * Copyright (c) 1980, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static char copyright[] =
36"@(#) Copyright (c) 1980, 1993\n\
37	The Regents of the University of California.  All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41static char sccsid[] = "@(#)main.c	8.1 (Berkeley) 6/20/93";
42#endif /* not lint */
43
44#define USE_OLD_TTY
45
46#include <sys/param.h>
47#include <sys/stat.h>
48#include <sys/resource.h>
49
50#include <ctype.h>
51#include <ctype.h>
52#include <fcntl.h>
53#include <setjmp.h>
54#include <sgtty.h>
55#include <signal.h>
56#include <stdlib.h>
57#include <string.h>
58#include <syslog.h>
59#include <time.h>
60#include <unistd.h>
61
62#include "gettytab.h"
63#include "pathnames.h"
64#include "extern.h"
65
66/*
67 * Set the amount of running time that getty should accumulate
68 * before deciding that something is wrong and exit.
69 */
70#define GETTY_TIMEOUT	60 /* seconds */
71
72struct	sgttyb tmode = {
73	0, 0, CERASE, CKILL, 0
74};
75struct	tchars tc = {
76	CINTR, CQUIT, CSTART,
77	CSTOP, CEOF, CBRK,
78};
79struct	ltchars ltc = {
80	CSUSP, CDSUSP, CRPRNT,
81	CFLUSH, CWERASE, CLNEXT
82};
83
84int crmod, digit, lower, upper;
85
86char	hostname[MAXHOSTNAMELEN];
87char	name[16];
88char	dev[] = _PATH_DEV;
89char	ttyn[32];
90char	*portselector();
91char	*ttyname();
92
93#define	OBUFSIZ		128
94#define	TABBUFSIZ	512
95
96char	defent[TABBUFSIZ];
97char	tabent[TABBUFSIZ];
98
99char	*env[128];
100
101char partab[] = {
102	0001,0201,0201,0001,0201,0001,0001,0201,
103	0202,0004,0003,0205,0005,0206,0201,0001,
104	0201,0001,0001,0201,0001,0201,0201,0001,
105	0001,0201,0201,0001,0201,0001,0001,0201,
106	0200,0000,0000,0200,0000,0200,0200,0000,
107	0000,0200,0200,0000,0200,0000,0000,0200,
108	0000,0200,0200,0000,0200,0000,0000,0200,
109	0200,0000,0000,0200,0000,0200,0200,0000,
110	0200,0000,0000,0200,0000,0200,0200,0000,
111	0000,0200,0200,0000,0200,0000,0000,0200,
112	0000,0200,0200,0000,0200,0000,0000,0200,
113	0200,0000,0000,0200,0000,0200,0200,0000,
114	0000,0200,0200,0000,0200,0000,0000,0200,
115	0200,0000,0000,0200,0000,0200,0200,0000,
116	0200,0000,0000,0200,0000,0200,0200,0000,
117	0000,0200,0200,0000,0200,0000,0000,0201
118};
119
120#define	ERASE	tmode.sg_erase
121#define	KILL	tmode.sg_kill
122#define	EOT	tc.t_eofc
123
124jmp_buf timeout;
125
126static void
127dingdong()
128{
129
130	alarm(0);
131	signal(SIGALRM, SIG_DFL);
132	longjmp(timeout, 1);
133}
134
135jmp_buf	intrupt;
136
137static void
138interrupt()
139{
140
141	signal(SIGINT, interrupt);
142	longjmp(intrupt, 1);
143}
144
145/*
146 * Action to take when getty is running too long.
147 */
148void
149timeoverrun(signo)
150	int signo;
151{
152
153	syslog(LOG_ERR, "getty exiting due to excessive running time\n");
154	exit(1);
155}
156
157static int	getname __P((void));
158static void	oflush __P((void));
159static void	prompt __P((void));
160static void	putchr __P((int));
161static void	putf __P((char *));
162static void	putpad __P((char *));
163static void	puts __P((char *));
164
165int
166main(argc, argv)
167	int argc;
168	char *argv[];
169{
170	extern char **environ;
171	char *tname;
172	long allflags;
173	int repcnt = 0;
174	struct rlimit limit;
175
176	signal(SIGINT, SIG_IGN);
177/*
178	signal(SIGQUIT, SIG_DFL);
179*/
180	openlog("getty", LOG_ODELAY|LOG_CONS, LOG_AUTH);
181	gethostname(hostname, sizeof(hostname));
182	if (hostname[0] == '\0')
183		strcpy(hostname, "Amnesiac");
184
185	/*
186	 * Limit running time to deal with broken or dead lines.
187	 */
188	(void)signal(SIGXCPU, timeoverrun);
189	limit.rlim_max = RLIM_INFINITY;
190	limit.rlim_cur = GETTY_TIMEOUT;
191	(void)setrlimit(RLIMIT_CPU, &limit);
192
193	/*
194	 * The following is a work around for vhangup interactions
195	 * which cause great problems getting window systems started.
196	 * If the tty line is "-", we do the old style getty presuming
197	 * that the file descriptors are already set up for us.
198	 * J. Gettys - MIT Project Athena.
199	 */
200	if (argc <= 2 || strcmp(argv[2], "-") == 0)
201	    strcpy(ttyn, ttyname(0));
202	else {
203	    int i;
204
205	    strcpy(ttyn, dev);
206	    strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
207	    if (strcmp(argv[0], "+") != 0) {
208		chown(ttyn, 0, 0);
209		chmod(ttyn, 0600);
210		revoke(ttyn);
211		/*
212		 * Delay the open so DTR stays down long enough to be detected.
213		 */
214		sleep(2);
215		while ((i = open(ttyn, O_RDWR)) == -1) {
216			if (repcnt % 10 == 0) {
217				syslog(LOG_ERR, "%s: %m", ttyn);
218				closelog();
219			}
220			repcnt++;
221			sleep(60);
222		}
223		login_tty(i);
224	    }
225	}
226
227	gettable("default", defent);
228	gendefaults();
229	tname = "default";
230	if (argc > 1)
231		tname = argv[1];
232	for (;;) {
233		int off;
234
235		gettable(tname, tabent);
236		if (OPset || EPset || APset)
237			APset++, OPset++, EPset++;
238		setdefaults();
239		off = 0;
240		ioctl(0, TIOCFLUSH, &off);	/* clear out the crap */
241		ioctl(0, FIONBIO, &off);	/* turn off non-blocking mode */
242		ioctl(0, FIOASYNC, &off);	/* ditto for async mode */
243		if (IS)
244			tmode.sg_ispeed = speed(IS);
245		else if (SP)
246			tmode.sg_ispeed = speed(SP);
247		if (OS)
248			tmode.sg_ospeed = speed(OS);
249		else if (SP)
250			tmode.sg_ospeed = speed(SP);
251		tmode.sg_flags = setflags(0);
252		ioctl(0, TIOCSETP, &tmode);
253		setchars();
254		ioctl(0, TIOCSETC, &tc);
255		if (HC)
256			ioctl(0, TIOCHPCL, 0);
257		if (AB) {
258			extern char *autobaud();
259
260			tname = autobaud();
261			continue;
262		}
263		if (PS) {
264			tname = portselector();
265			continue;
266		}
267		if (CL && *CL)
268			putpad(CL);
269		edithost(HE);
270		if (IM && *IM)
271			putf(IM);
272		if (setjmp(timeout)) {
273			tmode.sg_ispeed = tmode.sg_ospeed = 0;
274			ioctl(0, TIOCSETP, &tmode);
275			exit(1);
276		}
277		if (TO) {
278			signal(SIGALRM, dingdong);
279			alarm(TO);
280		}
281		if (getname()) {
282			register int i;
283
284			oflush();
285			alarm(0);
286			signal(SIGALRM, SIG_DFL);
287			if (name[0] == '-') {
288				puts("user names may not start with '-'.");
289				continue;
290			}
291			if (!(upper || lower || digit))
292				continue;
293			allflags = setflags(2);
294			tmode.sg_flags = allflags & 0xffff;
295			allflags >>= 16;
296			if (crmod || NL)
297				tmode.sg_flags |= CRMOD;
298			if (upper || UC)
299				tmode.sg_flags |= LCASE;
300			if (lower || LC)
301				tmode.sg_flags &= ~LCASE;
302			ioctl(0, TIOCSETP, &tmode);
303			ioctl(0, TIOCSLTC, &ltc);
304			ioctl(0, TIOCLSET, &allflags);
305			signal(SIGINT, SIG_DFL);
306			for (i = 0; environ[i] != (char *)0; i++)
307				env[i] = environ[i];
308			makeenv(&env[i]);
309
310			/*
311			 * this is what login was doing anyway.
312			 * soon we rewrite getty completely.
313			 */
314			set_ttydefaults(0);
315			limit.rlim_max = RLIM_INFINITY;
316			limit.rlim_cur = RLIM_INFINITY;
317			(void)setrlimit(RLIMIT_CPU, &limit);
318			execle(LO, "login", "-p", name, (char *) 0, env);
319			syslog(LOG_ERR, "%s: %m", LO);
320			exit(1);
321		}
322		alarm(0);
323		signal(SIGALRM, SIG_DFL);
324		signal(SIGINT, SIG_IGN);
325		if (NX && *NX)
326			tname = NX;
327	}
328}
329
330static int
331getname()
332{
333	register int c;
334	register char *np;
335	char cs;
336
337	/*
338	 * Interrupt may happen if we use CBREAK mode
339	 */
340	if (setjmp(intrupt)) {
341		signal(SIGINT, SIG_IGN);
342		return (0);
343	}
344	signal(SIGINT, interrupt);
345	tmode.sg_flags = setflags(0);
346	ioctl(0, TIOCSETP, &tmode);
347	tmode.sg_flags = setflags(1);
348	prompt();
349	if (PF > 0) {
350		oflush();
351		sleep(PF);
352		PF = 0;
353	}
354	ioctl(0, TIOCSETP, &tmode);
355	crmod = digit = lower = upper = 0;
356	np = name;
357	for (;;) {
358		oflush();
359		if (read(STDIN_FILENO, &cs, 1) <= 0)
360			exit(0);
361		if ((c = cs&0177) == 0)
362			return (0);
363		if (c == EOT)
364			exit(1);
365		if (c == '\r' || c == '\n' || np >= &name[sizeof name]) {
366			putf("\r\n");
367			break;
368		}
369		if (islower(c))
370			lower = 1;
371		else if (isupper(c))
372			upper = 1;
373		else if (c == ERASE || c == '#' || c == '\b') {
374			if (np > name) {
375				np--;
376				if (tmode.sg_ospeed >= B1200)
377					puts("\b \b");
378				else
379					putchr(cs);
380			}
381			continue;
382		} else if (c == KILL || c == '@') {
383			putchr(cs);
384			putchr('\r');
385			if (tmode.sg_ospeed < B1200)
386				putchr('\n');
387			/* this is the way they do it down under ... */
388			else if (np > name)
389				puts("                                     \r");
390			prompt();
391			np = name;
392			continue;
393		} else if (isdigit(c))
394			digit++;
395		if (IG && (c <= ' ' || c > 0176))
396			continue;
397		*np++ = c;
398		putchr(cs);
399	}
400	signal(SIGINT, SIG_IGN);
401	*np = 0;
402	if (c == '\r')
403		crmod = 1;
404	if (upper && !lower && !LC || UC)
405		for (np = name; *np; np++)
406			if (isupper(*np))
407				*np = tolower(*np);
408	return (1);
409}
410
411static
412short	tmspc10[] = {
413	0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5, 15
414};
415
416static void
417putpad(s)
418	register char *s;
419{
420	register pad = 0;
421	register mspc10;
422
423	if (isdigit(*s)) {
424		while (isdigit(*s)) {
425			pad *= 10;
426			pad += *s++ - '0';
427		}
428		pad *= 10;
429		if (*s == '.' && isdigit(s[1])) {
430			pad += s[1] - '0';
431			s += 2;
432		}
433	}
434
435	puts(s);
436	/*
437	 * If no delay needed, or output speed is
438	 * not comprehensible, then don't try to delay.
439	 */
440	if (pad == 0)
441		return;
442	if (tmode.sg_ospeed <= 0 ||
443	    tmode.sg_ospeed >= (sizeof tmspc10 / sizeof tmspc10[0]))
444		return;
445
446	/*
447	 * Round up by a half a character frame, and then do the delay.
448	 * Too bad there are no user program accessible programmed delays.
449	 * Transmitting pad characters slows many terminals down and also
450	 * loads the system.
451	 */
452	mspc10 = tmspc10[tmode.sg_ospeed];
453	pad += mspc10 / 2;
454	for (pad /= mspc10; pad > 0; pad--)
455		putchr(*PC);
456}
457
458static void
459puts(s)
460	register char *s;
461{
462	while (*s)
463		putchr(*s++);
464}
465
466char	outbuf[OBUFSIZ];
467int	obufcnt = 0;
468
469static void
470putchr(cc)
471	int cc;
472{
473	char c;
474
475	c = cc;
476	if (!NP) {
477		c |= partab[c&0177] & 0200;
478		if (OP)
479			c ^= 0200;
480	}
481	if (!UB) {
482		outbuf[obufcnt++] = c;
483		if (obufcnt >= OBUFSIZ)
484			oflush();
485	} else
486		write(STDOUT_FILENO, &c, 1);
487}
488
489static void
490oflush()
491{
492	if (obufcnt)
493		write(STDOUT_FILENO, outbuf, obufcnt);
494	obufcnt = 0;
495}
496
497static void
498prompt()
499{
500
501	putf(LM);
502	if (CO)
503		putchr('\n');
504}
505
506static void
507putf(cp)
508	register char *cp;
509{
510	extern char editedhost[];
511	time_t t;
512	char *slash, db[100];
513
514	while (*cp) {
515		if (*cp != '%') {
516			putchr(*cp++);
517			continue;
518		}
519		switch (*++cp) {
520
521		case 't':
522			slash = strrchr(ttyn, '/');
523			if (slash == (char *) 0)
524				puts(ttyn);
525			else
526				puts(&slash[1]);
527			break;
528
529		case 'h':
530			puts(editedhost);
531			break;
532
533		case 'd': {
534			static char fmt[] = "%l:% %P on %A, %d %B %Y";
535
536			fmt[4] = 'M';		/* I *hate* SCCS... */
537			(void)time(&t);
538			(void)strftime(db, sizeof(db), fmt, localtime(&t));
539			puts(db);
540			break;
541		}
542
543		case '%':
544			putchr('%');
545			break;
546		}
547		cp++;
548	}
549}
550