xref: /csrg-svn/libexec/getty/main.c (revision 18543)
1 #ifndef lint
2 static char sccsid[] = "@(#)main.c	4.7 (Berkeley) 85/04/01";
3 #endif
4 
5 /*
6  * getty -- adapt to terminal speed on dialup, and call login
7  *
8  * Melbourne getty, June 83, kre.
9  */
10 
11 #include <sgtty.h>
12 #include <signal.h>
13 #include <ctype.h>
14 #include <setjmp.h>
15 #include <syslog.h>
16 #include <sys/file.h>
17 #include "gettytab.h"
18 
19 extern	char **environ;
20 
21 struct	sgttyb tmode = {
22 	0, 0, CERASE, CKILL, 0
23 };
24 struct	tchars tc = {
25 	CINTR, CQUIT, CSTART,
26 	CSTOP, CEOF, CBRK,
27 };
28 struct	ltchars ltc = {
29 	CSUSP, CDSUSP, CRPRNT,
30 	CFLUSH, CWERASE, CLNEXT
31 };
32 
33 int	crmod;
34 int	upper;
35 int	lower;
36 int	digit;
37 
38 char	hostname[32];
39 char	name[16];
40 char	dev[] = "/dev/";
41 char	ctty[] = "/dev/console";
42 char	ttyn[32];
43 char	*portselector();
44 char	*ttyname();
45 
46 #define	OBUFSIZ		128
47 #define	TABBUFSIZ	512
48 
49 char	defent[TABBUFSIZ];
50 char	defstrs[TABBUFSIZ];
51 char	tabent[TABBUFSIZ];
52 char	tabstrs[TABBUFSIZ];
53 
54 char	*env[128];
55 
56 char partab[] = {
57 	0001,0201,0201,0001,0201,0001,0001,0201,
58 	0202,0004,0003,0205,0005,0206,0201,0001,
59 	0201,0001,0001,0201,0001,0201,0201,0001,
60 	0001,0201,0201,0001,0201,0001,0001,0201,
61 	0200,0000,0000,0200,0000,0200,0200,0000,
62 	0000,0200,0200,0000,0200,0000,0000,0200,
63 	0000,0200,0200,0000,0200,0000,0000,0200,
64 	0200,0000,0000,0200,0000,0200,0200,0000,
65 	0200,0000,0000,0200,0000,0200,0200,0000,
66 	0000,0200,0200,0000,0200,0000,0000,0200,
67 	0000,0200,0200,0000,0200,0000,0000,0200,
68 	0200,0000,0000,0200,0000,0200,0200,0000,
69 	0000,0200,0200,0000,0200,0000,0000,0200,
70 	0200,0000,0000,0200,0000,0200,0200,0000,
71 	0200,0000,0000,0200,0000,0200,0200,0000,
72 	0000,0200,0200,0000,0200,0000,0000,0201
73 };
74 
75 #define	ERASE	tmode.sg_erase
76 #define	KILL	tmode.sg_kill
77 #define	EOT	tc.t_eofc
78 
79 jmp_buf timeout;
80 
81 dingdong()
82 {
83 
84 	alarm(0);
85 	signal(SIGALRM, SIG_DFL);
86 	longjmp(timeout, 1);
87 }
88 
89 jmp_buf	intrupt;
90 
91 interrupt()
92 {
93 
94 	signal(SIGINT, interrupt);
95 	longjmp(intrupt, 1);
96 }
97 
98 main(argc, argv)
99 	char *argv[];
100 {
101 	char *tname;
102 	long allflags;
103 	int repcnt = 0;
104 
105 	signal(SIGINT, SIG_IGN);
106 /*
107 	signal(SIGQUIT, SIG_DFL);
108 */
109 	openlog("getty", LOG_ODELAY|LOG_CONS, 0);
110 	gethostname(hostname, sizeof(hostname));
111 	if (hostname[0] == '\0')
112 		strcpy(hostname, "Amnesiac");
113 	/*
114 	 * The following is a work around for vhangup interactions
115 	 * which cause great problems getting window systems started.
116 	 * If the tty line is "-", we do the old style getty presuming
117 	 * that the file descriptors are already set up for us.
118 	 * J. Gettys - MIT Project Athena.
119 	 */
120 	if (argc <= 2 || strcmp(argv[2], "-") == 0)
121 		strcpy(ttyn, ttyname(0));
122 	else {
123 		strcpy(ttyn, dev);
124 		strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
125 		chown(ttyn, 0, 0);
126 		chmod(ttyn, 0622);
127 		while (open(ttyn, O_RDWR) != 0) {
128 			if (repcnt % 10 == 0) {
129 				syslog(LOG_FAIL, "%s: %m", ttyn);
130 				closelog();
131 			}
132 			repcnt++;
133 			sleep(60);
134 		}
135 		signal(SIGHUP, SIG_IGN);
136 		vhangup();
137 		(void) open(ttyn, O_RDWR);
138 		close(0);
139 		dup(1);
140 		dup(0);
141 		signal(SIGHUP, SIG_DFL);
142 	}
143 
144 	gettable("default", defent, defstrs);
145 	gendefaults();
146 	tname = "default";
147 	if (argc > 1)
148 		tname = argv[1];
149 	for (;;) {
150 		int ldisp = OTTYDISC;
151 
152 		gettable(tname, tabent, tabstrs);
153 		if (OPset || EPset || APset)
154 			APset++, OPset++, EPset++;
155 		setdefaults();
156 		ioctl(0, TIOCFLUSH, 0);		/* clear out the crap */
157 		if (IS)
158 			tmode.sg_ispeed = speed(IS);
159 		else if (SP)
160 			tmode.sg_ispeed = speed(SP);
161 		if (OS)
162 			tmode.sg_ospeed = speed(OS);
163 		else if (SP)
164 			tmode.sg_ospeed = speed(SP);
165 		tmode.sg_flags = setflags(0);
166 		ioctl(0, TIOCSETP, &tmode);
167 		setchars();
168 		ioctl(0, TIOCSETC, &tc);
169 		ioctl(0, TIOCSETD, &ldisp);
170 		if (HC)
171 			ioctl(0, TIOCHPCL, 0);
172 		if (AB) {
173 			extern char *autobaud();
174 
175 			tname = autobaud();
176 			continue;
177 		}
178 		if (PS) {
179 			tname = portselector();
180 			continue;
181 		}
182 		if (CL && *CL)
183 			putpad(CL);
184 		edithost(HE);
185 		if (IM && *IM)
186 			putf(IM);
187 		if (setjmp(timeout)) {
188 			tmode.sg_ispeed = tmode.sg_ospeed = 0;
189 			ioctl(0, TIOCSETP, &tmode);
190 			exit(1);
191 		}
192 		if (TO) {
193 			signal(SIGALRM, dingdong);
194 			alarm(TO);
195 		}
196 		if (getname()) {
197 			register int i;
198 
199 			oflush();
200 			alarm(0);
201 			signal(SIGALRM, SIG_DFL);
202 			if (!(upper || lower || digit))
203 				continue;
204 			allflags = setflags(2);
205 			tmode.sg_flags = allflags & 0xffff;
206 			allflags >>= 16;
207 			if (crmod || NL)
208 				tmode.sg_flags |= CRMOD;
209 			if (upper || UC)
210 				tmode.sg_flags |= LCASE;
211 			if (lower || LC)
212 				tmode.sg_flags &= ~LCASE;
213 			ioctl(0, TIOCSETP, &tmode);
214 			ioctl(0, TIOCSLTC, &ltc);
215 			ioctl(0, TIOCLSET, &allflags);
216 			signal(SIGINT, SIG_DFL);
217 			for (i = 0; environ[i] != (char *)0; i++)
218 				env[i] = environ[i];
219 			makeenv(&env[i]);
220 			execle(LO, "login", "-p", name, (char *) 0, env);
221 			exit(1);
222 		}
223 		alarm(0);
224 		signal(SIGALRM, SIG_DFL);
225 		signal(SIGINT, SIG_IGN);
226 		if (NX && *NX)
227 			tname = NX;
228 	}
229 }
230 
231 getname()
232 {
233 	register char *np;
234 	register c;
235 	char cs;
236 
237 	/*
238 	 * Interrupt may happen if we use CBREAK mode
239 	 */
240 	if (setjmp(intrupt)) {
241 		signal(SIGINT, SIG_IGN);
242 		return (0);
243 	}
244 	signal(SIGINT, interrupt);
245 	tmode.sg_flags = setflags(0);
246 	ioctl(0, TIOCSETP, &tmode);
247 	tmode.sg_flags = setflags(1);
248 	prompt();
249 	if (PF > 0) {
250 		oflush();
251 		sleep(PF);
252 		PF = 0;
253 	}
254 	ioctl(0, TIOCSETP, &tmode);
255 	crmod = 0;
256 	upper = 0;
257 	lower = 0;
258 	digit = 0;
259 	np = name;
260 	for (;;) {
261 		oflush();
262 		if (read(0, &cs, 1) <= 0)
263 			exit(0);
264 		if ((c = cs&0177) == 0)
265 			return (0);
266 		if (c == EOT)
267 			exit(1);
268 		if (c == '\r' || c == '\n' || np >= &name[sizeof name]) {
269 			putf("\r\n");
270 			break;
271 		}
272 		if (c >= 'a' && c <= 'z')
273 			lower++;
274 		else if (c >= 'A' && c <= 'Z')
275 			upper++;
276 		else if (c == ERASE || c == '#' || c == '\b') {
277 			if (np > name) {
278 				np--;
279 				if (tmode.sg_ospeed >= B1200)
280 					puts("\b \b");
281 				else
282 					putchr(cs);
283 			}
284 			continue;
285 		} else if (c == KILL || c == '@') {
286 			putchr(cs);
287 			putchr('\r');
288 			if (tmode.sg_ospeed < B1200)
289 				putchr('\n');
290 			/* this is the way they do it down under ... */
291 			else if (np > name)
292 				puts("                                     \r");
293 			prompt();
294 			np = name;
295 			continue;
296 		} else if (c >= '0' && c <= '9')
297 			digit++;
298 		if (IG && (c <= ' ' || c > 0176))
299 			continue;
300 		*np++ = c;
301 		putchr(cs);
302 	}
303 	signal(SIGINT, SIG_IGN);
304 	*np = 0;
305 	if (c == '\r')
306 		crmod++;
307 	if (upper && !lower && !LC || UC)
308 		for (np = name; *np; np++)
309 			if (isupper(*np))
310 				*np = tolower(*np);
311 	return (1);
312 }
313 
314 static
315 short	tmspc10[] = {
316 	0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5, 15
317 };
318 
319 putpad(s)
320 	register char *s;
321 {
322 	register pad = 0;
323 	register mspc10;
324 
325 	if (isdigit(*s)) {
326 		while (isdigit(*s)) {
327 			pad *= 10;
328 			pad += *s++ - '0';
329 		}
330 		pad *= 10;
331 		if (*s == '.' && isdigit(s[1])) {
332 			pad += s[1] - '0';
333 			s += 2;
334 		}
335 	}
336 
337 	puts(s);
338 	/*
339 	 * If no delay needed, or output speed is
340 	 * not comprehensible, then don't try to delay.
341 	 */
342 	if (pad == 0)
343 		return;
344 	if (tmode.sg_ospeed <= 0 ||
345 	    tmode.sg_ospeed >= (sizeof tmspc10 / sizeof tmspc10[0]))
346 		return;
347 
348 	/*
349 	 * Round up by a half a character frame,
350 	 * and then do the delay.
351 	 * Too bad there are no user program accessible programmed delays.
352 	 * Transmitting pad characters slows many
353 	 * terminals down and also loads the system.
354 	 */
355 	mspc10 = tmspc10[tmode.sg_ospeed];
356 	pad += mspc10 / 2;
357 	for (pad /= mspc10; pad > 0; pad--)
358 		putchr(*PC);
359 }
360 
361 puts(s)
362 	register char *s;
363 {
364 
365 	while (*s)
366 		putchr(*s++);
367 }
368 
369 char	outbuf[OBUFSIZ];
370 int	obufcnt = 0;
371 
372 putchr(cc)
373 {
374 	char c;
375 
376 	c = cc;
377 	c |= partab[c&0177] & 0200;
378 	if (OP)
379 		c ^= 0200;
380 	if (!UB) {
381 		outbuf[obufcnt++] = c;
382 		if (obufcnt >= OBUFSIZ)
383 			oflush();
384 	} else
385 		write(1, &c, 1);
386 }
387 
388 oflush()
389 {
390 	if (obufcnt)
391 		write(1, outbuf, obufcnt);
392 	obufcnt = 0;
393 }
394 
395 prompt()
396 {
397 
398 	putf(LM);
399 	if (CO)
400 		putchr('\n');
401 }
402 
403 putf(cp)
404 	register char *cp;
405 {
406 	char *ttyn, *slash;
407 	char datebuffer[60];
408 	extern char editedhost[];
409 	extern char *ttyname(), *rindex();
410 
411 	while (*cp) {
412 		if (*cp != '%') {
413 			putchr(*cp++);
414 			continue;
415 		}
416 		switch (*++cp) {
417 
418 		case 't':
419 			ttyn = ttyname(0);
420 			slash = rindex(ttyn, '/');
421 			if (slash == (char *) 0)
422 				puts(ttyn);
423 			else
424 				puts(&slash[1]);
425 			break;
426 
427 		case 'h':
428 			puts(editedhost);
429 			break;
430 
431 		case 'd':
432 			get_date(datebuffer);
433 			puts(datebuffer);
434 			break;
435 
436 		case '%':
437 			putchr('%');
438 			break;
439 		}
440 		cp++;
441 	}
442 }
443