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