xref: /netbsd-src/libexec/getty/main.c (revision 62a8debe1dc62962e18a1c918def78666141273b)
1 /*	$NetBSD: main.c,v 1.58 2010/02/03 15:34:43 roy Exp $	*/
2 
3 /*-
4  * Copyright (c) 1980, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 
34 #ifndef lint
35 __COPYRIGHT("@(#) Copyright (c) 1980, 1993\
36  The Regents of the University of California.  All rights reserved.");
37 #endif /* not lint */
38 
39 #ifndef lint
40 #if 0
41 static char sccsid[] = "from: @(#)main.c	8.1 (Berkeley) 6/20/93";
42 #else
43 __RCSID("$NetBSD: main.c,v 1.58 2010/02/03 15:34:43 roy Exp $");
44 #endif
45 #endif /* not lint */
46 
47 #include <sys/param.h>
48 #include <sys/stat.h>
49 #include <termios.h>
50 #include <sys/ioctl.h>
51 #include <sys/resource.h>
52 #include <sys/utsname.h>
53 
54 #include <ctype.h>
55 #include <errno.h>
56 #include <fcntl.h>
57 #include <limits.h>
58 #include <pwd.h>
59 #include <setjmp.h>
60 #include <signal.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <syslog.h>
64 #include <term.h>
65 #include <time.h>
66 #include <ttyent.h>
67 #include <unistd.h>
68 #include <util.h>
69 
70 #include "gettytab.h"
71 #include "pathnames.h"
72 #include "extern.h"
73 
74 extern char editedhost[];
75 
76 /*
77  * Set the amount of running time that getty should accumulate
78  * before deciding that something is wrong and exit.
79  */
80 #define GETTY_TIMEOUT	60 /* seconds */
81 
82 /* defines for auto detection of incoming PPP calls (->PAP/CHAP) */
83 
84 #define PPP_FRAME           0x7e  /* PPP Framing character */
85 #define PPP_STATION         0xff  /* "All Station" character */
86 #define PPP_ESCAPE          0x7d  /* Escape Character */
87 #define PPP_CONTROL         0x03  /* PPP Control Field */
88 #define PPP_CONTROL_ESCAPED 0x23  /* PPP Control Field, escaped */
89 #define PPP_LCP_HI          0xc0  /* LCP protocol - high byte */
90 #define PPP_LCP_LOW         0x21  /* LCP protocol - low byte */
91 
92 struct termios tmode, omode;
93 
94 int crmod, digit_or_punc, lower, upper;
95 
96 char	hostname[MAXHOSTNAMELEN + 1];
97 struct	utsname kerninfo;
98 char	name[LOGIN_NAME_MAX];
99 char	dev[] = _PATH_DEV;
100 char	ttyn[32];
101 char	lockfile[512];
102 uid_t	ttyowner;
103 char	*rawttyn;
104 
105 #define	OBUFSIZ		128
106 #define	TABBUFSIZ	512
107 
108 char	defent[TABBUFSIZ];
109 char	tabent[TABBUFSIZ];
110 
111 char	*env[128];
112 
113 const unsigned char partab[] = {
114 	0001,0201,0201,0001,0201,0001,0001,0201,
115 	0202,0004,0003,0205,0005,0206,0201,0001,
116 	0201,0001,0001,0201,0001,0201,0201,0001,
117 	0001,0201,0201,0001,0201,0001,0001,0201,
118 	0200,0000,0000,0200,0000,0200,0200,0000,
119 	0000,0200,0200,0000,0200,0000,0000,0200,
120 	0000,0200,0200,0000,0200,0000,0000,0200,
121 	0200,0000,0000,0200,0000,0200,0200,0000,
122 	0200,0000,0000,0200,0000,0200,0200,0000,
123 	0000,0200,0200,0000,0200,0000,0000,0200,
124 	0000,0200,0200,0000,0200,0000,0000,0200,
125 	0200,0000,0000,0200,0000,0200,0200,0000,
126 	0000,0200,0200,0000,0200,0000,0000,0200,
127 	0200,0000,0000,0200,0000,0200,0200,0000,
128 	0200,0000,0000,0200,0000,0200,0200,0000,
129 	0000,0200,0200,0000,0200,0000,0000,0201
130 };
131 
132 #define	ERASE	tmode.c_cc[VERASE]
133 #define	KILL	tmode.c_cc[VKILL]
134 #define	EOT	tmode.c_cc[VEOF]
135 
136 static void	clearscreen(void);
137 
138 jmp_buf timeout;
139 
140 static void
141 /*ARGSUSED*/
142 dingdong(int signo)
143 {
144 
145 	(void)alarm(0);
146 	(void)signal(SIGALRM, SIG_DFL);
147 	longjmp(timeout, 1);
148 }
149 
150 jmp_buf	intrupt;
151 
152 static void
153 /*ARGSUSED*/
154 interrupt(int signo)
155 {
156 
157 	(void)signal(SIGINT, interrupt);
158 	longjmp(intrupt, 1);
159 }
160 
161 /*
162  * Action to take when getty is running too long.
163  */
164 static void
165 /*ARGSUSED*/
166 timeoverrun(int signo)
167 {
168 
169 	syslog(LOG_ERR, "getty exiting due to excessive running time");
170 	exit(1);
171 }
172 
173 static int	getname(void);
174 static void	oflush(void);
175 static void	prompt(void);
176 static void	putchr(int);
177 static void	putf(const char *);
178 static void	putpad(const char *);
179 static void	xputs(const char *);
180 
181 int
182 main(int argc, char *argv[], char *envp[])
183 {
184 	const char *progname;
185 	char *tname;
186 	int repcnt = 0, failopenlogged = 0, uugetty = 0, first_time = 1;
187 	struct rlimit limit;
188 	struct passwd *pw;
189 	int rval;
190 
191 	(void)signal(SIGINT, SIG_IGN);
192 	openlog("getty", LOG_PID, LOG_AUTH);
193 	(void)gethostname(hostname, sizeof(hostname));
194 	hostname[sizeof(hostname) - 1] = '\0';
195 	if (hostname[0] == '\0')
196 		(void)strlcpy(hostname, "Amnesiac", sizeof(hostname));
197 	(void)uname(&kerninfo);
198 
199 	progname = getprogname();
200 	if (progname[0] == 'u' && progname[1] == 'u')
201 		uugetty = 1;
202 
203 	/*
204 	 * Find id of uucp login (if present) so we can chown tty properly.
205 	 */
206 	if (uugetty && (pw = getpwnam("uucp")))
207 		ttyowner = pw->pw_uid;
208 	else
209 		ttyowner = 0;
210 
211 	/*
212 	 * Limit running time to deal with broken or dead lines.
213 	 */
214 	(void)signal(SIGXCPU, timeoverrun);
215 	limit.rlim_max = RLIM_INFINITY;
216 	limit.rlim_cur = GETTY_TIMEOUT;
217 	(void)setrlimit(RLIMIT_CPU, &limit);
218 
219 	/*
220 	 * The following is a work around for vhangup interactions
221 	 * which cause great problems getting window systems started.
222 	 * If the tty line is "-", we do the old style getty presuming
223 	 * that the file descriptors are already set up for us.
224 	 * J. Gettys - MIT Project Athena.
225 	 */
226 	if (argc <= 2 || strcmp(argv[2], "-") == 0) {
227 		(void)strlcpy(ttyn, ttyname(0), sizeof(ttyn));
228 	}
229 	else {
230 		int i;
231 
232 		rawttyn = argv[2];
233 		(void)strlcpy(ttyn, dev, sizeof(ttyn));
234 		(void)strlcat(ttyn, argv[2], sizeof(ttyn));
235 		if (uugetty)  {
236 			(void)chown(ttyn, ttyowner, 0);
237 			(void)strlcpy(lockfile, _PATH_LOCK,
238 				sizeof(lockfile));
239 			(void)strlcat(lockfile, argv[2],
240 				sizeof(lockfile));
241 			/*
242 			 * wait for lockfiles to go away before we try
243 			 * to open
244 			 */
245 			if (pidlock(lockfile, 0, 0, 0) != 0)  {
246 				syslog(LOG_ERR,
247 					"%s: can't create lockfile", ttyn);
248 				exit(1);
249 			}
250 			(void)unlink(lockfile);
251 		}
252 		if (strcmp(argv[0], "+") != 0) {
253 			(void)chown(ttyn, ttyowner, 0);
254 			(void)chmod(ttyn, 0600);
255 			(void)revoke(ttyn);
256 			if (ttyaction(ttyn, "getty", "root"))
257 				syslog(LOG_WARNING, "%s: ttyaction failed",
258 					ttyn);
259 			/*
260 			 * Delay the open so DTR stays down long enough
261 			 * to be detected.
262 			 */
263 			(void)sleep(2);
264 			while ((i = open(ttyn, O_RDWR)) == -1) {
265 				if ((repcnt % 10 == 0) &&
266 				    (errno != ENXIO || !failopenlogged)) {
267 					syslog(LOG_WARNING, "%s: %m", ttyn);
268 					closelog();
269 					failopenlogged = 1;
270 				}
271 				repcnt++;
272 				(void)sleep(60);
273 			}
274 			if (uugetty && pidlock(lockfile, 0, 0, 0) != 0)  {
275 				syslog(LOG_ERR, "%s: can't create lockfile",
276 					ttyn);
277 				exit(1);
278 			}
279 			if (uugetty)
280 				(void)chown(lockfile, ttyowner, 0);
281 			(void)login_tty(i);
282 		}
283 	}
284 
285 	/* Start with default tty settings */
286 	if (tcgetattr(0, &tmode) < 0) {
287 		syslog(LOG_ERR, "%s: %m", ttyn);
288 		exit(1);
289 	}
290 	omode = tmode;
291 
292 	gettable("default", defent);
293 	gendefaults();
294 	tname = "default";
295 	if (argc > 1)
296 		tname = argv[1];
297 	for (;;) {
298 		int off;
299 
300 		rval = 0;
301 		gettable(tname, tabent);
302 		if (OPset || EPset || APset)
303 			APset++, OPset++, EPset++;
304 		setdefaults();
305 		off = 0;
306 		(void)tcflush(0, TCIOFLUSH);	/* clear out the crap */
307 		(void)ioctl(0, FIONBIO, &off);	/* turn off non-blocking mode */
308 		(void)ioctl(0, FIOASYNC, &off);	/* ditto for async mode */
309 
310 		if (IS)
311 			(void)cfsetispeed(&tmode, (speed_t)IS);
312 		else if (SP)
313 			(void)cfsetispeed(&tmode, (speed_t)SP);
314 		if (OS)
315 			(void)cfsetospeed(&tmode, (speed_t)OS);
316 		else if (SP)
317 			(void)cfsetospeed(&tmode, (speed_t)SP);
318 		setflags(0);
319 		setchars();
320 		if (tcsetattr(0, TCSANOW, &tmode) < 0) {
321 			syslog(LOG_ERR, "%s: %m", ttyn);
322 			exit(1);
323 		}
324 		if (AB) {
325 			tname = autobaud();
326 			continue;
327 		}
328 		if (PS) {
329 			tname = portselector();
330 			continue;
331 		}
332 		if (CS)
333 			clearscreen();
334 		if (CL && *CL)
335 			putpad(CL);
336 		edithost(HE);
337 
338 		/*
339 		 * If this is the first time through this, and an
340 		 * issue file has been given, then send it.
341 		 */
342 		if (first_time != 0 && IF != NULL) {
343 			char buf[_POSIX2_LINE_MAX];
344 			FILE *fp;
345 
346 			if ((fp = fopen(IF, "r")) != NULL) {
347 				while (fgets(buf, sizeof(buf) - 1, fp) != NULL)
348 					putf(buf);
349 				(void)fclose(fp);
350 			}
351 		}
352 		first_time = 0;
353 
354 		if (IM && *IM)
355 			putf(IM);
356 		oflush();
357 		if (setjmp(timeout)) {
358 			tmode.c_ispeed = tmode.c_ospeed = 0;
359 			(void)tcsetattr(0, TCSANOW, &tmode);
360 			exit(1);
361 		}
362 		if (TO) {
363 			(void)signal(SIGALRM, dingdong);
364 			(void)alarm((unsigned int)TO);
365 		}
366 		if (NN) {
367 			name[0] = '\0';
368 			lower = 1;
369 			upper = digit_or_punc = 0;
370 		} else if (AL) {
371 			const char *p = AL;
372 			char *q = name;
373 
374 			while (*p && q < &name[sizeof name - 1]) {
375 				if (isupper((unsigned char)*p))
376 					upper = 1;
377 				else if (islower((unsigned char)*p))
378 					lower = 1;
379 				else if (isdigit((unsigned char)*p))
380 					digit_or_punc = 1;
381 				*q++ = *p++;
382 			}
383 		} else if ((rval = getname()) == 2) {
384 			setflags(2);
385 			(void)execle(PP, "ppplogin", ttyn, (char *) 0, env);
386 			syslog(LOG_ERR, "%s: %m", PP);
387 			exit(1);
388 		}
389 
390 		if (rval || AL || NN) {
391 			int i;
392 
393 			oflush();
394 			(void)alarm(0);
395 			(void)signal(SIGALRM, SIG_DFL);
396 			if (name[0] == '-') {
397 				xputs("user names may not start with '-'.");
398 				continue;
399 			}
400 			if (!(upper || lower || digit_or_punc))
401 				continue;
402 			setflags(2);
403 			if (crmod) {
404 				tmode.c_iflag |= ICRNL;
405 				tmode.c_oflag |= ONLCR;
406 			}
407 #if XXX
408 			if (upper || UC)
409 				tmode.sg_flags |= LCASE;
410 			if (lower || LC)
411 				tmode.sg_flags &= ~LCASE;
412 #endif
413 			if (tcsetattr(0, TCSANOW, &tmode) < 0) {
414 				syslog(LOG_ERR, "%s: %m", ttyn);
415 				exit(1);
416 			}
417 			(void)signal(SIGINT, SIG_DFL);
418 			for (i = 0; envp[i] != NULL; i++)
419 				env[i] = envp[i];
420 			makeenv(&env[i]);
421 
422 			limit.rlim_max = RLIM_INFINITY;
423 			limit.rlim_cur = RLIM_INFINITY;
424 			(void)setrlimit(RLIMIT_CPU, &limit);
425 			if (NN)
426 				(void)execle(LO, "login", AL ? "-fp" : "-p",
427 				    NULL, env);
428 			else
429 				(void)execle(LO, "login", AL ? "-fp" : "-p",
430 				    "--", name, NULL, env);
431 			syslog(LOG_ERR, "%s: %m", LO);
432 			exit(1);
433 		}
434 		(void)alarm(0);
435 		(void)signal(SIGALRM, SIG_DFL);
436 		(void)signal(SIGINT, SIG_IGN);
437 		if (NX && *NX)
438 			tname = NX;
439 		if (uugetty)
440 			(void)unlink(lockfile);
441 	}
442 }
443 
444 static int
445 getname(void)
446 {
447 	int c;
448 	char *np;
449 	unsigned char cs;
450 	int ppp_state, ppp_connection;
451 
452 	/*
453 	 * Interrupt may happen if we use CBREAK mode
454 	 */
455 	if (setjmp(intrupt)) {
456 		(void)signal(SIGINT, SIG_IGN);
457 		return (0);
458 	}
459 	(void)signal(SIGINT, interrupt);
460 	setflags(1);
461 	prompt();
462 	if (PF > 0) {
463 		oflush();
464 		(void)sleep((unsigned int)PF);
465 		PF = 0;
466 	}
467 	if (tcsetattr(0, TCSANOW, &tmode) < 0) {
468 		syslog(LOG_ERR, "%s: %m", ttyn);
469 		exit(1);
470 	}
471 	crmod = digit_or_punc = lower = upper = 0;
472 	ppp_state = ppp_connection = 0;
473 	np = name;
474 	for (;;) {
475 		oflush();
476 		if (read(STDIN_FILENO, &cs, 1) <= 0)
477 			exit(0);
478 		if ((c = cs&0177) == 0)
479 			return (0);
480 
481 		/*
482 		 * PPP detection state machine..
483 		 * Look for sequences:
484 		 * PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or
485 		 * PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC)
486 		 * See RFC1662.
487 		 * Derived from code from Michael Hancock <michaelh@cet.co.jp>
488 		 * and Erik 'PPP' Olson <eriko@wrq.com>
489 		 */
490 		if (PP && cs == PPP_FRAME) {
491 			ppp_state = 1;
492 		} else if (ppp_state == 1 && cs == PPP_STATION) {
493 			ppp_state = 2;
494 		} else if (ppp_state == 2 && cs == PPP_ESCAPE) {
495 			ppp_state = 3;
496 		} else if ((ppp_state == 2 && cs == PPP_CONTROL) ||
497 		    (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) {
498 			ppp_state = 4;
499 		} else if (ppp_state == 4 && cs == PPP_LCP_HI) {
500 			ppp_state = 5;
501 		} else if (ppp_state == 5 && cs == PPP_LCP_LOW) {
502 			ppp_connection = 1;
503 			break;
504 		} else {
505 			ppp_state = 0;
506 		}
507 
508 		if (c == EOT)
509 			exit(1);
510 		if (c == '\r' || c == '\n' ||
511 		    np >= &name[LOGIN_NAME_MAX - 1]) {
512 			*np = '\0';
513 			putf("\r\n");
514 			break;
515 		}
516 		if (islower(c))
517 			lower = 1;
518 		else if (isupper(c))
519 			upper = 1;
520 		else if (c == ERASE || c == '#' || c == '\b') {
521 			if (np > name) {
522 				np--;
523 				if (cfgetospeed(&tmode) >= 1200)
524 					xputs("\b \b");
525 				else
526 					putchr(cs);
527 			}
528 			continue;
529 		} else if (c == KILL || c == '@') {
530 			putchr(cs);
531 			putchr('\r');
532 			if (cfgetospeed(&tmode) < 1200)
533 				putchr('\n');
534 			/* this is the way they do it down under ... */
535 			else if (np > name)
536 				xputs(
537 				    "                                     \r");
538 			prompt();
539 			np = name;
540 			continue;
541 		} else if (isdigit(c) || c == '_')
542 			digit_or_punc = 1;
543 		if (IG && (c <= ' ' || c > 0176))
544 			continue;
545 		*np++ = c;
546 		putchr(cs);
547 
548 		/*
549 		 * An MS-Windows direct connect PPP "client" won't send its
550 		 * first PPP packet until we respond to its "CLIENT" poll
551 		 * with a CRLF sequence.  We cater to yet another broken
552 		 * implementation of a previously-standard protocol...
553 		 */
554 		*np = '\0';
555 		if (strstr(name, "CLIENT"))
556 			putf("\r\n");
557 	}
558 	(void)signal(SIGINT, SIG_IGN);
559 	*np = 0;
560 	if (c == '\r')
561 		crmod = 1;
562 	if ((upper && !lower && !LC) || UC)
563 		for (np = name; *np; np++)
564 			*np = tolower((unsigned char)*np);
565 	return (1 + ppp_connection);
566 }
567 
568 static void
569 putpad(const char *s)
570 {
571 	int pad = 0;
572 	speed_t ospd = cfgetospeed(&tmode);
573 
574 	if (isdigit((unsigned char)*s)) {
575 		while (isdigit((unsigned char)*s)) {
576 			pad *= 10;
577 			pad += *s++ - '0';
578 		}
579 		pad *= 10;
580 		if (*s == '.' && isdigit((unsigned char)s[1])) {
581 			pad += s[1] - '0';
582 			s += 2;
583 		}
584 	}
585 
586 	xputs(s);
587 	/*
588 	 * If no delay needed, or output speed is
589 	 * not comprehensible, then don't try to delay.
590 	 */
591 	if (pad == 0)
592 		return;
593 
594 	/*
595 	 * Round up by a half a character frame, and then do the delay.
596 	 * Too bad there are no user program accessible programmed delays.
597 	 * Transmitting pad characters slows many terminals down and also
598 	 * loads the system.
599 	 */
600 	pad = (pad * ospd + 50000) / 100000;
601 	while (pad--)
602 		putchr(*PC);
603 }
604 
605 static void
606 xputs(const char *s)
607 {
608 	while (*s)
609 		putchr(*s++);
610 }
611 
612 char	outbuf[OBUFSIZ];
613 size_t	obufcnt = 0;
614 
615 static void
616 putchr(int cc)
617 {
618 	unsigned char c;
619 
620 	c = cc;
621 	if (!NP) {
622 		c |= partab[c&0177] & 0200;
623 		if (OP)
624 			c ^= 0200;
625 	}
626 	if (!UB) {
627 		outbuf[obufcnt++] = c;
628 		if (obufcnt >= OBUFSIZ)
629 			oflush();
630 	} else
631 		(void)write(STDOUT_FILENO, &c, 1);
632 }
633 
634 static void
635 oflush(void)
636 {
637 	if (obufcnt)
638 		(void)write(STDOUT_FILENO, outbuf, obufcnt);
639 	obufcnt = 0;
640 }
641 
642 static void
643 prompt(void)
644 {
645 
646 	putf(LM);
647 	if (CO)
648 		putchr('\n');
649 }
650 
651 static void
652 putf(const char *cp)
653 {
654 	time_t t;
655 	char *slash, db[100];
656 
657 	while (*cp) {
658 		if (*cp != '%') {
659 			putchr(*cp++);
660 			continue;
661 		}
662 		switch (*++cp) {
663 
664 		case 't':
665 			if ((slash = strstr(ttyn, "/pts/")) == NULL)
666 				slash = strrchr(ttyn, '/');
667 			if (slash == NULL)
668 				xputs(ttyn);
669 			else
670 				xputs(&slash[1]);
671 			break;
672 
673 		case 'h':
674 			xputs(editedhost);
675 			break;
676 
677 		case 'd':
678 			(void)time(&t);
679 			(void)strftime(db, sizeof(db),
680 			    "%l:%M%p on %A, %d %B %Y", localtime(&t));
681 			xputs(db);
682 			break;
683 
684 		case 's':
685 			xputs(kerninfo.sysname);
686 			break;
687 
688 		case 'm':
689 			xputs(kerninfo.machine);
690 			break;
691 
692 		case 'r':
693 			xputs(kerninfo.release);
694 			break;
695 
696 		case 'v':
697 			xputs(kerninfo.version);
698 			break;
699 
700 		case '%':
701 			putchr('%');
702 			break;
703 		}
704 		if (*cp)
705 			cp++;
706 	}
707 }
708 
709 static void
710 clearscreen(void)
711 {
712 	struct ttyent *typ;
713 	int err;
714 
715 	if (rawttyn == NULL)
716 		return;
717 
718 	typ = getttynam(rawttyn);
719 
720 	if ((typ == NULL) || (typ->ty_type == NULL) ||
721 	    (typ->ty_type[0] == 0))
722 		return;
723 
724 	if (setupterm(typ->ty_type, 0, &err) == ERR)
725 		return;
726 
727 	if (clear_screen)
728 		putpad(clear_screen);
729 
730 	del_curterm(cur_term);
731 	cur_term = NULL;
732 }
733