main.c revision 9875
1/*-
2 * Copyright (c) 1980 The Regents of the University of California.
3 * 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
35char copyright[] =
36"@(#) Copyright (c) 1980 The Regents of the University of California.\n\
37 All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41static char sccsid[] = "@(#)main.c	5.16 (Berkeley) 3/27/91";
42#endif /* not lint */
43
44#define USE_OLD_TTY
45
46#include <sys/param.h>
47#include <sys/stat.h>
48#include <signal.h>
49#include <fcntl.h>
50#include <sgtty.h>
51#include <time.h>
52#include <ctype.h>
53#include <setjmp.h>
54#include <syslog.h>
55#include <unistd.h>
56#include <ctype.h>
57#include <stdlib.h>
58#include <string.h>
59#include "gettytab.h"
60#include "pathnames.h"
61
62struct	sgttyb tmode = {
63	0, 0, CERASE, CKILL, 0
64};
65struct	tchars tc = {
66	CINTR, CQUIT, CSTART,
67	CSTOP, CEOF, CBRK,
68};
69struct	ltchars ltc = {
70	CSUSP, CDSUSP, CRPRNT,
71	CFLUSH, CWERASE, CLNEXT
72};
73
74int crmod, digit, lower, upper;
75
76char	hostname[MAXHOSTNAMELEN];
77char	name[16];
78char	dev[] = _PATH_DEV;
79char	ttyn[32];
80char	*portselector();
81char	*ttyname();
82
83#define	OBUFSIZ		128
84#define	TABBUFSIZ	512
85
86char	defent[TABBUFSIZ];
87char	defstrs[TABBUFSIZ];
88char	tabent[TABBUFSIZ];
89char	tabstrs[TABBUFSIZ];
90
91char	*env[128];
92
93char partab[] = {
94	0001,0201,0201,0001,0201,0001,0001,0201,
95	0202,0004,0003,0205,0005,0206,0201,0001,
96	0201,0001,0001,0201,0001,0201,0201,0001,
97	0001,0201,0201,0001,0201,0001,0001,0201,
98	0200,0000,0000,0200,0000,0200,0200,0000,
99	0000,0200,0200,0000,0200,0000,0000,0200,
100	0000,0200,0200,0000,0200,0000,0000,0200,
101	0200,0000,0000,0200,0000,0200,0200,0000,
102	0200,0000,0000,0200,0000,0200,0200,0000,
103	0000,0200,0200,0000,0200,0000,0000,0200,
104	0000,0200,0200,0000,0200,0000,0000,0200,
105	0200,0000,0000,0200,0000,0200,0200,0000,
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,0201
110};
111
112#define	ERASE	tmode.sg_erase
113#define	KILL	tmode.sg_kill
114#define	EOT	tc.t_eofc
115
116jmp_buf timeout;
117
118static void
119dingdong()
120{
121
122	alarm(0);
123	signal(SIGALRM, SIG_DFL);
124	longjmp(timeout, 1);
125}
126
127jmp_buf	intrupt;
128
129static void
130interrupt()
131{
132
133	signal(SIGINT, interrupt);
134	longjmp(intrupt, 1);
135}
136
137main(argc, argv)
138	int argc;
139	char **argv;
140{
141	extern	char **environ;
142	char *tname;
143	int repcnt = 0;
144
145	signal(SIGINT, SIG_IGN);
146	signal(SIGQUIT, SIG_IGN);
147
148	openlog("getty", LOG_ODELAY|LOG_CONS, LOG_AUTH);
149	gethostname(hostname, sizeof(hostname));
150	if (hostname[0] == '\0')
151		strcpy(hostname, "Amnesiac");
152	/*
153	 * The following is a work around for vhangup interactions
154	 * which cause great problems getting window systems started.
155	 * If the tty line is "-", we do the old style getty presuming
156	 * that the file descriptors are already set up for us.
157	 * J. Gettys - MIT Project Athena.
158	 */
159	if (argc <= 2 || strcmp(argv[2], "-") == 0)
160	    strcpy(ttyn, ttyname(0));
161	else {
162	    int i;
163
164	    strcpy(ttyn, dev);
165	    strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
166	    if (strcmp(argv[0], "+") != 0) {
167		chown(ttyn, 0, 0);
168		chmod(ttyn, 0600);
169		revoke(ttyn);
170		while ((i = open(ttyn, O_RDWR)) == -1) {
171			if (repcnt % 10 == 0) {
172				syslog(LOG_ERR, "%s: %m", ttyn);
173				closelog();
174			}
175			repcnt++;
176			sleep(60);
177		}
178		login_tty(i);
179	    }
180	}
181
182	gettable("default", defent, defstrs);
183	gendefaults();
184	tname = "default";
185	if (argc > 1)
186		tname = argv[1];
187	for (;;) {
188		int off = 0;
189		int flushboth = 0;
190		struct sgttyb fake;
191
192		gettable(tname, tabent, tabstrs);
193		if (OPset || EPset || APset)
194			APset++, OPset++, EPset++;
195		setdefaults();
196		ioctl(0, TIOCFLUSH, &flushboth);         /* clear out the crap */
197		ioctl(0, FIONBIO, &off);	/* turn off non-blocking mode */
198		ioctl(0, FIOASYNC, &off);	/* ditto for async mode */
199		ioctl(0, TIOCGETP, &fake);      /* initialize kernel termios */
200		if (IS)
201			tmode.sg_ispeed = speed(IS);
202		else if (SP)
203			tmode.sg_ispeed = speed(SP);
204		if (OS)
205			tmode.sg_ospeed = speed(OS);
206		else if (SP)
207			tmode.sg_ospeed = speed(SP);
208		set_tmode(0);
209		setchars();
210		ioctl(0, TIOCSETC, &tc);
211		if (HC)
212			ioctl(0, TIOCHPCL, 0);
213		if (AB) {
214			extern char *autobaud();
215
216			tname = autobaud();
217			continue;
218		}
219		if (PS) {
220			tname = portselector();
221			continue;
222		}
223		if (CL && *CL)
224			putpad(CL);
225		edithost(HE);
226		if (IM && *IM)
227			putf(IM);
228		if (setjmp(timeout)) {
229			tmode.sg_ispeed = tmode.sg_ospeed = 0;
230			ioctl(0, TIOCSETP, &tmode);
231			exit(1);
232		}
233		if (TO) {
234			signal(SIGALRM, dingdong);
235			alarm(TO);
236		}
237		if (getname()) {
238			register int i;
239
240			alarm(0);
241			signal(SIGALRM, SIG_DFL);
242			oflush();
243			if (name[0] == '-') {
244				puts("user names may not start with '-'.");
245				continue;
246			}
247			if (!(upper || lower || digit))
248				continue;
249			set_tmode(2);
250			ioctl(0, TIOCSLTC, &ltc);
251			for (i = 0; environ[i] != (char *)0; i++)
252				env[i] = environ[i];
253			makeenv(&env[i]);
254
255			execle(LO, "login", "-p", name, (char *) 0, env);
256			syslog(LOG_ERR, "%s: %m", LO);
257			exit(1);
258		}
259		signal(SIGINT, SIG_IGN);
260		alarm(0);
261		signal(SIGALRM, SIG_DFL);
262		if (NX && *NX)
263			tname = NX;
264	}
265}
266
267getname()
268{
269	register int c;
270	register char *np;
271	char cs;
272	int flushin = 1 /*FREAD*/;
273
274	/*
275	 * Interrupt may happen if we use CBREAK mode
276	 */
277	if (setjmp(intrupt)) {
278		signal(SIGINT, SIG_IGN);
279		return (0);
280	}
281	signal(SIGINT, interrupt);
282	ioctl(0, TIOCFLUSH, &flushin);         /* purge any input */
283	prompt();
284	oflush();
285	if (PF > 0) {
286		sleep(PF);
287		PF = 0;
288	}
289	set_tmode(1);
290	crmod = digit = lower = upper = 0;
291	np = name;
292	for (;;) {
293		oflush();
294		if (read(STDIN_FILENO, &cs, 1) <= 0)
295			exit(0);
296		if ((c = cs&0177) == 0)
297			return (0);
298		if (c == EOT || c == 4 /*^D*/)
299			exit(1);
300		if (c == '\r' || c == '\n' || np >= &name[sizeof name]) {
301			putf("\r\n");
302			break;
303		}
304		if (islower(c))
305			lower = 1;
306		else if (isupper(c))
307			upper = 1;
308		else if (c == ERASE || c == '\b' || c == 0177) {
309			if (np > name) {
310				np--;
311				if (tmode.sg_ospeed >= B1200)
312					puts("\b \b");
313				else
314					putchr(cs);
315			}
316			continue;
317		} else if (c == KILL || c == 025 /*^U*/) {
318			putchr('\r');
319			if (tmode.sg_ospeed < B1200)
320				putchr('\n');
321			/* this is the way they do it down under ... */
322			else if (np > name)
323				puts("                                     \r");
324			prompt();
325			np = name;
326			continue;
327		} else if (isdigit(c))
328			digit++;
329		if (IG && (c <= ' ' || c > 0176))
330			continue;
331		*np++ = c;
332		putchr(cs);
333	}
334	signal(SIGINT, SIG_IGN);
335	*np = 0;
336	if (c == '\r')
337		crmod = 1;
338	if (upper && !lower && !LC || UC)
339		for (np = name; *np; np++)
340			if (isupper(*np))
341				*np = tolower(*np);
342	return (1);
343}
344
345static
346short	tmspc10[] = {
347	0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5, 15
348};
349
350putpad(s)
351	register char *s;
352{
353	register pad = 0;
354	register mspc10;
355
356	if (isdigit(*s)) {
357		while (isdigit(*s)) {
358			pad *= 10;
359			pad += *s++ - '0';
360		}
361		pad *= 10;
362		if (*s == '.' && isdigit(s[1])) {
363			pad += s[1] - '0';
364			s += 2;
365		}
366	}
367
368	puts(s);
369	/*
370	 * If no delay needed, or output speed is
371	 * not comprehensible, then don't try to delay.
372	 */
373	if (pad == 0)
374		return;
375	if (tmode.sg_ospeed <= 0 ||
376	    tmode.sg_ospeed >= (sizeof tmspc10 / sizeof tmspc10[0]))
377		return;
378
379	/*
380	 * Round up by a half a character frame, and then do the delay.
381	 * Too bad there are no user program accessible programmed delays.
382	 * Transmitting pad characters slows many terminals down and also
383	 * loads the system.
384	 */
385	mspc10 = tmspc10[tmode.sg_ospeed];
386	pad += mspc10 / 2;
387	for (pad /= mspc10; pad > 0; pad--)
388		putchr(*PC);
389}
390
391puts(s)
392	register char *s;
393{
394	while (*s)
395		putchr(*s++);
396}
397
398char	outbuf[OBUFSIZ];
399int	obufcnt = 0;
400
401putchr(cc)
402{
403	char c;
404
405	c = cc;
406	if (!NP) {
407		c |= partab[c&0177] & 0200;
408		if (OP)
409			c ^= 0200;
410	}
411	if (!UB) {
412		outbuf[obufcnt++] = c;
413		if (obufcnt >= OBUFSIZ)
414			oflush();
415	} else
416		write(STDOUT_FILENO, &c, 1);
417}
418
419oflush()
420{
421	if (obufcnt)
422		write(STDOUT_FILENO, outbuf, obufcnt);
423	obufcnt = 0;
424}
425
426prompt()
427{
428
429	putf(LM);
430	if (CO)
431		putchr('\n');
432}
433
434putf(cp)
435	register char *cp;
436{
437	extern char editedhost[];
438	time_t t;
439	char *slash, db[100];
440
441	while (*cp) {
442		if (*cp != '%') {
443			putchr(*cp++);
444			continue;
445		}
446		switch (*++cp) {
447
448		case 't':
449			slash = rindex(ttyn, '/');
450			if (slash == (char *) 0)
451				puts(ttyn);
452			else
453				puts(&slash[1]);
454			break;
455
456		case 'h':
457			puts(editedhost);
458			break;
459
460		case 'd': {
461			static char fmt[] = "%l:% %p on %A, %d %B %Y";
462
463			fmt[4] = 'M';		/* I *hate* SCCS... */
464			(void)time(&t);
465			(void)strftime(db, sizeof(db), fmt, localtime(&t));
466			puts(db);
467			break;
468		}
469
470		case '%':
471			putchr('%');
472			break;
473		}
474		cp++;
475	}
476}
477
478/*
479 * The conversions from sgttyb to termios make LITOUT and PASS8 affect
480 * the parity.  So every TIOCSETP ioctl has to be paired with a TIOCLSET
481 * ioctl (at least if LITOUT or PASS8 has changed, and PASS8 may vary
482 * with 'n').
483 */
484set_tmode(n)
485	int n;
486{
487	long allflags;
488
489	allflags = setflags(n);
490	tmode.sg_flags = allflags & 0xffff;
491	allflags >>= 16;
492	if (n == 2) {
493		if (crmod || NL)
494			tmode.sg_flags |= CRMOD;
495		if (upper || UC)
496			tmode.sg_flags |= LCASE;
497		if (lower || LC)
498			tmode.sg_flags &= ~LCASE;
499	}
500	ioctl(0, TIOCSETP, &tmode);
501	ioctl(0, TIOCLSET, &allflags);
502}
503