main.c revision 15659
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
41/*static char sccsid[] = "from: @(#)main.c	8.1 (Berkeley) 6/20/93";*/
42static char rcsid[] = "$Id: main.c,v 1.9 1996/05/05 19:01:10 joerg Exp $";
43#endif /* not lint */
44
45#include <sys/param.h>
46#include <sys/stat.h>
47#include <sys/ioctl.h>
48#include <sys/resource.h>
49#include <sys/ttydefaults.h>
50#include <sys/utsname.h>
51#include <errno.h>
52#include <signal.h>
53#include <fcntl.h>
54#include <time.h>
55#include <ctype.h>
56#include <fcntl.h>
57#include <libutil.h>
58#include <locale.h>
59#include <setjmp.h>
60#include <signal.h>
61#include <stdlib.h>
62#include <string.h>
63#include <syslog.h>
64#include <termios.h>
65#include <time.h>
66#include <unistd.h>
67
68#include "gettytab.h"
69#include "pathnames.h"
70#include "extern.h"
71
72/*
73 * Set the amount of running time that getty should accumulate
74 * before deciding that something is wrong and exit.
75 */
76#define GETTY_TIMEOUT	60 /* seconds */
77
78#undef CTRL
79#define CTRL(x)  (x&037)
80
81struct termios tmode, omode;
82
83int crmod, digit, lower, upper;
84
85char	hostname[MAXHOSTNAMELEN];
86struct utsname kerninfo;
87char	name[16];
88char	dev[] = _PATH_DEV;
89char	ttyn[32];
90
91#define	OBUFSIZ		128
92#define	TABBUFSIZ	512
93
94char	defent[TABBUFSIZ];
95char	tabent[TABBUFSIZ];
96
97char	*env[128];
98
99char partab[] = {
100	0001,0201,0201,0001,0201,0001,0001,0201,
101	0202,0004,0003,0205,0005,0206,0201,0001,
102	0201,0001,0001,0201,0001,0201,0201,0001,
103	0001,0201,0201,0001,0201,0001,0001,0201,
104	0200,0000,0000,0200,0000,0200,0200,0000,
105	0000,0200,0200,0000,0200,0000,0000,0200,
106	0000,0200,0200,0000,0200,0000,0000,0200,
107	0200,0000,0000,0200,0000,0200,0200,0000,
108	0200,0000,0000,0200,0000,0200,0200,0000,
109	0000,0200,0200,0000,0200,0000,0000,0200,
110	0000,0200,0200,0000,0200,0000,0000,0200,
111	0200,0000,0000,0200,0000,0200,0200,0000,
112	0000,0200,0200,0000,0200,0000,0000,0200,
113	0200,0000,0000,0200,0000,0200,0200,0000,
114	0200,0000,0000,0200,0000,0200,0200,0000,
115	0000,0200,0200,0000,0200,0000,0000,0201
116};
117
118#define	ERASE	tmode.c_cc[VERASE]
119#define	KILL	tmode.c_cc[VKILL]
120#define	EOT	tmode.c_cc[VEOF]
121
122jmp_buf timeout;
123
124static void	dingdong __P((int));
125static int	getname __P((void));
126static void	interrupt __P((int));
127static void	oflush __P((void));
128static void	prompt __P((void));
129static void	putchr __P((int));
130static void	putf __P((const char *));
131static void	putpad __P((const char *));
132static void	puts __P((const char *));
133static void	timeoverrun __P((int));
134
135int		main __P((int, char **));
136
137static void
138dingdong(signo)
139	int signo;
140{
141	alarm(0);
142	longjmp(timeout, 1);
143}
144
145jmp_buf	intrupt;
146
147static void
148interrupt(signo)
149	int signo;
150{
151	longjmp(intrupt, 1);
152}
153
154/*
155 * Action to take when getty is running too long.
156 */
157static void
158timeoverrun(signo)
159	int signo;
160{
161
162	syslog(LOG_ERR, "getty exiting due to excessive running time\n");
163	exit(1);
164}
165
166int
167main(argc, argv)
168	int argc;
169	char **argv;
170{
171	extern	char **environ;
172	const char *tname;
173	int repcnt = 0, failopenlogged = 0;
174	struct rlimit limit;
175
176	signal(SIGINT, SIG_IGN);
177	signal(SIGQUIT, SIG_IGN);
178
179	openlog("getty", LOG_ODELAY|LOG_CONS|LOG_PID, LOG_AUTH);
180	gethostname(hostname, sizeof(hostname));
181	if (hostname[0] == '\0')
182		strcpy(hostname, "Amnesiac");
183
184	/*
185	 * Limit running time to deal with broken or dead lines.
186	 */
187	(void)signal(SIGXCPU, timeoverrun);
188	limit.rlim_max = RLIM_INFINITY;
189	limit.rlim_cur = GETTY_TIMEOUT;
190	(void)setrlimit(RLIMIT_CPU, &limit);
191
192	/*
193	 * The following is a work around for vhangup interactions
194	 * which cause great problems getting window systems started.
195	 * If the tty line is "-", we do the old style getty presuming
196	 * that the file descriptors are already set up for us.
197	 * J. Gettys - MIT Project Athena.
198	 */
199	if (argc <= 2 || strcmp(argv[2], "-") == 0)
200	    strcpy(ttyn, ttyname(0));
201	else {
202	    int i;
203
204	    strcpy(ttyn, dev);
205	    strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
206	    if (strcmp(argv[0], "+") != 0) {
207		chown(ttyn, 0, 0);
208		chmod(ttyn, 0600);
209		revoke(ttyn);
210		while ((i = open(ttyn, O_RDWR)) == -1) {
211			if ((repcnt % 10 == 0) &&
212			    (errno != ENXIO || !failopenlogged)) {
213				syslog(LOG_ERR, "%s: %m", ttyn);
214				closelog();
215				failopenlogged = 1;
216			}
217			repcnt++;
218			sleep(60);
219		}
220		login_tty(i);
221	    }
222	}
223
224	/* Start with default tty settings */
225	if (tcgetattr(0, &tmode) < 0) {
226		syslog(LOG_ERR, "%s: %m", ttyn);
227		exit(1);
228	}
229	/*
230	 * Don't rely on the driver too much, and initialize crucial
231	 * things according to <sys/ttydefaults.h>.  Avoid clobbering
232	 * the c_cc[] settings however, the console drivers might wish
233	 * to leave their idea of the preferred VERASE key value
234	 * there.
235	 */
236	tmode.c_iflag = TTYDEF_IFLAG;
237	tmode.c_oflag = TTYDEF_OFLAG;
238	tmode.c_lflag = TTYDEF_LFLAG;
239	tmode.c_cflag = TTYDEF_CFLAG;
240	omode = tmode;
241
242	gettable("default", defent);
243	gendefaults();
244	tname = "default";
245	if (argc > 1)
246		tname = argv[1];
247	for (;;) {
248		int off = 0;
249
250		gettable(tname, tabent);
251		if (OPset || EPset || APset)
252			APset++, OPset++, EPset++;
253		setdefaults();
254		off = 0;
255		(void)tcflush(0, TCIOFLUSH);	/* clear out the crap */
256		ioctl(0, FIONBIO, &off);	/* turn off non-blocking mode */
257		ioctl(0, FIOASYNC, &off);	/* ditto for async mode */
258
259		if (IS)
260			cfsetispeed(&tmode, speed(IS));
261		else if (SP)
262			cfsetispeed(&tmode, speed(SP));
263		if (OS)
264			cfsetospeed(&tmode, speed(OS));
265		else if (SP)
266			cfsetospeed(&tmode, speed(SP));
267		setflags(0);
268		setchars();
269		if (tcsetattr(0, TCSANOW, &tmode) < 0) {
270			syslog(LOG_ERR, "%s: %m", ttyn);
271			exit(1);
272		}
273		if (AB) {
274			tname = autobaud();
275			continue;
276		}
277		if (PS) {
278			tname = portselector();
279			continue;
280		}
281		if (CL && *CL)
282			putpad(CL);
283		edithost(HE);
284		if (IM && *IM)
285			putf(IM);
286		if (setjmp(timeout)) {
287			cfsetispeed(&tmode, B0);
288			cfsetospeed(&tmode, B0);
289			(void)tcsetattr(0, TCSANOW, &tmode);
290			exit(1);
291		}
292		if (TO) {
293			signal(SIGALRM, dingdong);
294			alarm(TO);
295		}
296		if (getname()) {
297			register int i;
298
299			oflush();
300			alarm(0);
301			signal(SIGALRM, SIG_DFL);
302			if (name[0] == '-') {
303				puts("user names may not start with '-'.");
304				continue;
305			}
306			if (!(upper || lower || digit))
307				continue;
308			setflags(2);
309			if (crmod) {
310				tmode.c_iflag |= ICRNL;
311				tmode.c_oflag |= ONLCR;
312			}
313#if REALLY_OLD_TTYS
314			if (upper || UC)
315				tmode.sg_flags |= LCASE;
316			if (lower || LC)
317				tmode.sg_flags &= ~LCASE;
318#endif
319			if (tcsetattr(0, TCSANOW, &tmode) < 0) {
320				syslog(LOG_ERR, "%s: %m", ttyn);
321				exit(1);
322			}
323			signal(SIGINT, SIG_DFL);
324			for (i = 0; environ[i] != (char *)0; i++)
325				env[i] = environ[i];
326			makeenv(&env[i]);
327
328			limit.rlim_max = RLIM_INFINITY;
329			limit.rlim_cur = RLIM_INFINITY;
330			(void)setrlimit(RLIMIT_CPU, &limit);
331			execle(LO, "login", "-p", name, (char *) 0, env);
332			syslog(LOG_ERR, "%s: %m", LO);
333			exit(1);
334		}
335		alarm(0);
336		signal(SIGALRM, SIG_DFL);
337		signal(SIGINT, SIG_IGN);
338		if (NX && *NX)
339			tname = NX;
340	}
341}
342
343static int
344getname()
345{
346	register int c;
347	register char *np;
348	char cs;
349
350	/*
351	 * Interrupt may happen if we use CBREAK mode
352	 */
353	if (setjmp(intrupt)) {
354		signal(SIGINT, SIG_IGN);
355		return (0);
356	}
357	signal(SIGINT, interrupt);
358	setflags(1);
359	prompt();
360	oflush();
361	if (PF > 0) {
362		sleep(PF);
363		PF = 0;
364	}
365	if (tcsetattr(0, TCSANOW, &tmode) < 0) {
366		syslog(LOG_ERR, "%s: %m", ttyn);
367		exit(1);
368	}
369	crmod = digit = lower = upper = 0;
370	np = name;
371	for (;;) {
372		oflush();
373		if (read(STDIN_FILENO, &cs, 1) <= 0)
374			exit(0);
375		if ((c = cs&0177) == 0)
376			return (0);
377		if (c == EOT || c == CTRL('d'))
378			exit(1);
379		if (c == '\r' || c == '\n' || np >= &name[sizeof name]) {
380			putf("\r\n");
381			break;
382		}
383		if (islower(c))
384			lower = 1;
385		else if (isupper(c))
386			upper = 1;
387		else if (c == ERASE || c == '\b' || c == 0177) {
388			if (np > name) {
389				np--;
390				if (cfgetospeed(&tmode) >= 1200)
391					puts("\b \b");
392				else
393					putchr(cs);
394			}
395			continue;
396		} else if (c == KILL || c == CTRL('u')) {
397			putchr('\r');
398			if (cfgetospeed(&tmode) < 1200)
399				putchr('\n');
400			/* this is the way they do it down under ... */
401			else if (np > name)
402				puts("                                     \r");
403			prompt();
404			np = name;
405			continue;
406		} else if (isdigit(c))
407			digit++;
408		if (IG && (c <= ' ' || c > 0176))
409			continue;
410		*np++ = c;
411		putchr(cs);
412	}
413	signal(SIGINT, SIG_IGN);
414	*np = 0;
415	if (c == '\r')
416		crmod = 1;
417	if ((upper && !lower && !LC) || UC)
418		for (np = name; *np; np++)
419			if (isupper(*np))
420				*np = tolower(*np);
421	return (1);
422}
423
424static void
425putpad(s)
426	register const char *s;
427{
428	register pad = 0;
429	speed_t ospeed = cfgetospeed(&tmode);
430
431	if (isdigit(*s)) {
432		while (isdigit(*s)) {
433			pad *= 10;
434			pad += *s++ - '0';
435		}
436		pad *= 10;
437		if (*s == '.' && isdigit(s[1])) {
438			pad += s[1] - '0';
439			s += 2;
440		}
441	}
442
443	puts(s);
444	/*
445	 * If no delay needed, or output speed is
446	 * not comprehensible, then don't try to delay.
447	 */
448	if (pad == 0 || ospeed <= 0)
449		return;
450
451	/*
452	 * Round up by a half a character frame, and then do the delay.
453	 * Too bad there are no user program accessible programmed delays.
454	 * Transmitting pad characters slows many terminals down and also
455	 * loads the system.
456	 */
457	pad = (pad * ospeed + 50000) / 100000;
458	while (pad--)
459		putchr(*PC);
460}
461
462static void
463puts(s)
464	register const char *s;
465{
466	while (*s)
467		putchr(*s++);
468}
469
470char	outbuf[OBUFSIZ];
471int	obufcnt = 0;
472
473static void
474putchr(cc)
475	int cc;
476{
477	char c;
478
479	c = cc;
480	if (!NP) {
481		c |= partab[c&0177] & 0200;
482		if (OP)
483			c ^= 0200;
484	}
485	if (!UB) {
486		outbuf[obufcnt++] = c;
487		if (obufcnt >= OBUFSIZ)
488			oflush();
489	} else
490		write(STDOUT_FILENO, &c, 1);
491}
492
493static void
494oflush()
495{
496	if (obufcnt)
497		write(STDOUT_FILENO, outbuf, obufcnt);
498	obufcnt = 0;
499}
500
501static void
502prompt()
503{
504
505	putf(LM);
506	if (CO)
507		putchr('\n');
508}
509
510static void
511putf(cp)
512	register const char *cp;
513{
514	extern char editedhost[];
515	time_t t;
516	char *slash, db[100];
517
518	while (*cp) {
519		if (*cp != '%') {
520			putchr(*cp++);
521			continue;
522		}
523		switch (*++cp) {
524
525		case 't':
526			slash = strrchr(ttyn, '/');
527			if (slash == (char *) 0)
528				puts(ttyn);
529			else
530				puts(&slash[1]);
531			break;
532
533		case 'h':
534			puts(editedhost);
535			break;
536
537		case 'd': {
538			t = (time_t)0;
539			(void)time(&t);
540			if (Lo)
541				(void)setlocale(LC_TIME, Lo);
542			(void)strftime(db, sizeof(db), "%+", localtime(&t));
543			puts(db);
544			break;
545
546		case 's':
547			puts(kerninfo.sysname);
548			break;
549
550		case 'm':
551			puts(kerninfo.machine);
552			break;
553
554		case 'r':
555			puts(kerninfo.release);
556			break;
557
558		case 'v':
559			puts(kerninfo.version);
560			break;
561		}
562
563		case '%':
564			putchr('%');
565			break;
566		}
567		cp++;
568	}
569}
570