main.c revision 2223
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 *));
164extern void	reset_fbtab __P((char *));
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	/* Read the FBTAB file and check if we have to reset perms/ownership */
228	reset_fbtab(ttyn);
229
230	gettable("default", defent);
231	gendefaults();
232	tname = "default";
233	if (argc > 1)
234		tname = argv[1];
235	for (;;) {
236		int off;
237
238		gettable(tname, tabent);
239		if (OPset || EPset || APset)
240			APset++, OPset++, EPset++;
241		setdefaults();
242		off = 0;
243		ioctl(0, TIOCFLUSH, &off);	/* clear out the crap */
244		ioctl(0, FIONBIO, &off);	/* turn off non-blocking mode */
245		ioctl(0, FIOASYNC, &off);	/* ditto for async mode */
246		if (IS)
247			tmode.sg_ispeed = speed(IS);
248		else if (SP)
249			tmode.sg_ispeed = speed(SP);
250		if (OS)
251			tmode.sg_ospeed = speed(OS);
252		else if (SP)
253			tmode.sg_ospeed = speed(SP);
254		tmode.sg_flags = setflags(0);
255		ioctl(0, TIOCSETP, &tmode);
256		setchars();
257		ioctl(0, TIOCSETC, &tc);
258		if (HC)
259			ioctl(0, TIOCHPCL, 0);
260		if (AB) {
261			extern char *autobaud();
262
263			tname = autobaud();
264			continue;
265		}
266		if (PS) {
267			tname = portselector();
268			continue;
269		}
270		if (CL && *CL)
271			putpad(CL);
272		edithost(HE);
273		if (IM && *IM)
274			putf(IM);
275		if (setjmp(timeout)) {
276			tmode.sg_ispeed = tmode.sg_ospeed = 0;
277			ioctl(0, TIOCSETP, &tmode);
278			exit(1);
279		}
280		if (TO) {
281			signal(SIGALRM, dingdong);
282			alarm(TO);
283		}
284		if (getname()) {
285			register int i;
286
287			oflush();
288			alarm(0);
289			signal(SIGALRM, SIG_DFL);
290			if (name[0] == '-') {
291				puts("user names may not start with '-'.");
292				continue;
293			}
294			if (!(upper || lower || digit))
295				continue;
296			allflags = setflags(2);
297			tmode.sg_flags = allflags & 0xffff;
298			allflags >>= 16;
299			if (crmod || NL)
300				tmode.sg_flags |= CRMOD;
301			if (upper || UC)
302				tmode.sg_flags |= LCASE;
303			if (lower || LC)
304				tmode.sg_flags &= ~LCASE;
305			ioctl(0, TIOCSETP, &tmode);
306			ioctl(0, TIOCSLTC, &ltc);
307			ioctl(0, TIOCLSET, &allflags);
308			signal(SIGINT, SIG_DFL);
309			for (i = 0; environ[i] != (char *)0; i++)
310				env[i] = environ[i];
311			makeenv(&env[i]);
312
313			/*
314			 * this is what login was doing anyway.
315			 * soon we rewrite getty completely.
316			 */
317			set_ttydefaults(0);
318			limit.rlim_max = RLIM_INFINITY;
319			limit.rlim_cur = RLIM_INFINITY;
320			(void)setrlimit(RLIMIT_CPU, &limit);
321			execle(LO, "login", "-p", name, (char *) 0, env);
322			syslog(LOG_ERR, "%s: %m", LO);
323			exit(1);
324		}
325		alarm(0);
326		signal(SIGALRM, SIG_DFL);
327		signal(SIGINT, SIG_IGN);
328		if (NX && *NX)
329			tname = NX;
330	}
331}
332
333static int
334getname()
335{
336	register int c;
337	register char *np;
338	char cs;
339
340	/*
341	 * Interrupt may happen if we use CBREAK mode
342	 */
343	if (setjmp(intrupt)) {
344		signal(SIGINT, SIG_IGN);
345		return (0);
346	}
347	signal(SIGINT, interrupt);
348	tmode.sg_flags = setflags(0);
349	ioctl(0, TIOCSETP, &tmode);
350	tmode.sg_flags = setflags(1);
351	prompt();
352	if (PF > 0) {
353		oflush();
354		sleep(PF);
355		PF = 0;
356	}
357	ioctl(0, TIOCSETP, &tmode);
358	crmod = digit = lower = upper = 0;
359	np = name;
360	for (;;) {
361		oflush();
362		if (read(STDIN_FILENO, &cs, 1) <= 0)
363			exit(0);
364		if ((c = cs&0177) == 0)
365			return (0);
366		if (c == EOT)
367			exit(1);
368		if (c == '\r' || c == '\n' || np >= &name[sizeof name]) {
369			putf("\r\n");
370			break;
371		}
372		if (islower(c))
373			lower = 1;
374		else if (isupper(c))
375			upper = 1;
376		else if (c == ERASE || c == '#' || c == '\b') {
377			if (np > name) {
378				np--;
379				if (tmode.sg_ospeed >= B1200)
380					puts("\b \b");
381				else
382					putchr(cs);
383			}
384			continue;
385		} else if (c == KILL || c == '@') {
386			putchr(cs);
387			putchr('\r');
388			if (tmode.sg_ospeed < B1200)
389				putchr('\n');
390			/* this is the way they do it down under ... */
391			else if (np > name)
392				puts("                                     \r");
393			prompt();
394			np = name;
395			continue;
396		} else if (isdigit(c))
397			digit++;
398		if (IG && (c <= ' ' || c > 0176))
399			continue;
400		*np++ = c;
401		putchr(cs);
402	}
403	signal(SIGINT, SIG_IGN);
404	*np = 0;
405	if (c == '\r')
406		crmod = 1;
407	if (upper && !lower && !LC || UC)
408		for (np = name; *np; np++)
409			if (isupper(*np))
410				*np = tolower(*np);
411	return (1);
412}
413
414static
415short	tmspc10[] = {
416	0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5, 15
417};
418
419static void
420putpad(s)
421	register char *s;
422{
423	register pad = 0;
424	register mspc10;
425
426	if (isdigit(*s)) {
427		while (isdigit(*s)) {
428			pad *= 10;
429			pad += *s++ - '0';
430		}
431		pad *= 10;
432		if (*s == '.' && isdigit(s[1])) {
433			pad += s[1] - '0';
434			s += 2;
435		}
436	}
437
438	puts(s);
439	/*
440	 * If no delay needed, or output speed is
441	 * not comprehensible, then don't try to delay.
442	 */
443	if (pad == 0)
444		return;
445	if (tmode.sg_ospeed <= 0 ||
446	    tmode.sg_ospeed >= (sizeof tmspc10 / sizeof tmspc10[0]))
447		return;
448
449	/*
450	 * Round up by a half a character frame, and then do the delay.
451	 * Too bad there are no user program accessible programmed delays.
452	 * Transmitting pad characters slows many terminals down and also
453	 * loads the system.
454	 */
455	mspc10 = tmspc10[tmode.sg_ospeed];
456	pad += mspc10 / 2;
457	for (pad /= mspc10; pad > 0; pad--)
458		putchr(*PC);
459}
460
461static void
462puts(s)
463	register char *s;
464{
465	while (*s)
466		putchr(*s++);
467}
468
469char	outbuf[OBUFSIZ];
470int	obufcnt = 0;
471
472static void
473putchr(cc)
474	int cc;
475{
476	char c;
477
478	c = cc;
479	if (!NP) {
480		c |= partab[c&0177] & 0200;
481		if (OP)
482			c ^= 0200;
483	}
484	if (!UB) {
485		outbuf[obufcnt++] = c;
486		if (obufcnt >= OBUFSIZ)
487			oflush();
488	} else
489		write(STDOUT_FILENO, &c, 1);
490}
491
492static void
493oflush()
494{
495	if (obufcnt)
496		write(STDOUT_FILENO, outbuf, obufcnt);
497	obufcnt = 0;
498}
499
500static void
501prompt()
502{
503
504	putf(LM);
505	if (CO)
506		putchr('\n');
507}
508
509static void
510putf(cp)
511	register char *cp;
512{
513	extern char editedhost[];
514	time_t t;
515	char *slash, db[100];
516
517	while (*cp) {
518		if (*cp != '%') {
519			putchr(*cp++);
520			continue;
521		}
522		switch (*++cp) {
523
524		case 't':
525			slash = strrchr(ttyn, '/');
526			if (slash == (char *) 0)
527				puts(ttyn);
528			else
529				puts(&slash[1]);
530			break;
531
532		case 'h':
533			puts(editedhost);
534			break;
535
536		case 'd': {
537			static char fmt[] = "%l:% %P on %A, %d %B %Y";
538
539			fmt[4] = 'M';		/* I *hate* SCCS... */
540			(void)time(&t);
541			(void)strftime(db, sizeof(db), fmt, localtime(&t));
542			puts(db);
543			break;
544		}
545
546		case '%':
547			putchr('%');
548			break;
549		}
550		cp++;
551	}
552}
553