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