xref: /minix3/libexec/getty/main.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1 /*	$NetBSD: main.c,v 1.64 2013/08/12 13:54:33 joerg 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.64 2013/08/12 13:54:33 joerg Exp $");
44 #endif
45 #endif /* not lint */
46 
47 #include <sys/param.h>
48 #include <sys/ioctl.h>
49 #include <sys/resource.h>
50 #include <sys/utsname.h>
51 
52 #include <ctype.h>
53 #include <errno.h>
54 #include <fcntl.h>
55 #include <limits.h>
56 #include <pwd.h>
57 #include <setjmp.h>
58 #include <signal.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <syslog.h>
63 #include <term.h>
64 #include <termios.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 sigjmp_buf timeout;
139 
140 __dead static void
141 /*ARGSUSED*/
dingdong(int signo)142 dingdong(int signo)
143 {
144 
145 	(void)alarm(0);
146 	(void)signal(SIGALRM, SIG_DFL);
147 	siglongjmp(timeout, 1);
148 }
149 
150 sigjmp_buf intrupt;
151 
152 __dead static void
153 /*ARGSUSED*/
interrupt(int signo)154 interrupt(int signo)
155 {
156 
157 	(void)signal(SIGINT, interrupt);
158 	siglongjmp(intrupt, 1);
159 }
160 
161 #if !defined(__minix)
162 /*
163  * Action to take when getty is running too long.
164  */
165 __dead static void
166 /*ARGSUSED*/
timeoverrun(int signo)167 timeoverrun(int signo)
168 {
169 
170 	syslog(LOG_ERR, "getty exiting due to excessive running time");
171 	exit(1);
172 }
173 #endif /* !defined(__minix) */
174 
175 static int	getname(void);
176 static void	oflush(void);
177 static void	prompt(void);
178 static int	putchr(int);
179 static void	putf(const char *);
180 static void	xputs(const char *);
181 
182 #define putpad(s) tputs(s, 1, putchr)
183 
184 int
main(int argc,char * argv[],char * envp[])185 main(int argc, char *argv[], char *envp[])
186 {
187 	const char *progname;
188 	int repcnt = 0, failopenlogged = 0, first_time = 1;
189 	struct rlimit limit;
190 	struct passwd *pw;
191 	int rval;
192 	/* this is used past the siglongjmp, so make sure it is not cached
193 	   in registers that might become invalid. */
194 	volatile int uugetty = 0;
195 	const char * volatile tname = "default";
196 
197 	(void)signal(SIGINT, SIG_IGN);
198 	openlog("getty", LOG_PID, LOG_AUTH);
199 	(void)gethostname(hostname, sizeof(hostname));
200 	hostname[sizeof(hostname) - 1] = '\0';
201 	if (hostname[0] == '\0')
202 		(void)strlcpy(hostname, "Amnesiac", sizeof(hostname));
203 	(void)uname(&kerninfo);
204 
205 	progname = getprogname();
206 	if (progname[0] == 'u' && progname[1] == 'u')
207 		uugetty = 1;
208 
209 	/*
210 	 * Find id of uucp login (if present) so we can chown tty properly.
211 	 */
212 	if (uugetty && (pw = getpwnam("uucp")))
213 		ttyowner = pw->pw_uid;
214 	else
215 		ttyowner = 0;
216 
217 	/*
218 	 * Limit running time to deal with broken or dead lines.
219 	 */
220 #if !defined(__minix)
221 	(void)signal(SIGXCPU, timeoverrun);
222 #endif /* !defined(__minix) */
223 	limit.rlim_max = RLIM_INFINITY;
224 	limit.rlim_cur = GETTY_TIMEOUT;
225 	(void)setrlimit(RLIMIT_CPU, &limit);
226 
227 	/*
228 	 * The following is a work around for vhangup interactions
229 	 * which cause great problems getting window systems started.
230 	 * If the tty line is "-", we do the old style getty presuming
231 	 * that the file descriptors are already set up for us.
232 	 * J. Gettys - MIT Project Athena.
233 	 */
234 	if (argc <= 2 || strcmp(argv[2], "-") == 0) {
235 		(void)strlcpy(ttyn, ttyname(0), sizeof(ttyn));
236 	}
237 	else {
238 		int i;
239 
240 		rawttyn = argv[2];
241 		(void)strlcpy(ttyn, dev, sizeof(ttyn));
242 		(void)strlcat(ttyn, argv[2], sizeof(ttyn));
243 		if (uugetty)  {
244 			(void)chown(ttyn, ttyowner, 0);
245 			(void)strlcpy(lockfile, _PATH_LOCK,
246 				sizeof(lockfile));
247 			(void)strlcat(lockfile, argv[2],
248 				sizeof(lockfile));
249 			/*
250 			 * wait for lockfiles to go away before we try
251 			 * to open
252 			 */
253 			if (pidlock(lockfile, 0, 0, 0) != 0)  {
254 				syslog(LOG_ERR,
255 					"%s: can't create lockfile", ttyn);
256 				exit(1);
257 			}
258 			(void)unlink(lockfile);
259 		}
260 		if (strcmp(argv[0], "+") != 0) {
261 			(void)chown(ttyn, ttyowner, 0);
262 			(void)chmod(ttyn, 0600);
263 #if !defined(__minix)
264 			(void)revoke(ttyn);
265 #endif /* !defined(__minix) */
266 			if (ttyaction(ttyn, "getty", "root"))
267 				syslog(LOG_WARNING, "%s: ttyaction failed",
268 					ttyn);
269 			/*
270 			 * Delay the open so DTR stays down long enough
271 			 * to be detected.
272 			 */
273 			(void)sleep(2);
274 			while ((i = open(ttyn, O_RDWR)) == -1) {
275 				if ((repcnt % 10 == 0) &&
276 				    (errno != ENXIO || !failopenlogged)) {
277 					syslog(LOG_WARNING, "%s: %m", ttyn);
278 					closelog();
279 					failopenlogged = 1;
280 				}
281 				repcnt++;
282 				(void)sleep(60);
283 			}
284 			if (uugetty && pidlock(lockfile, 0, 0, 0) != 0)  {
285 				syslog(LOG_ERR, "%s: can't create lockfile",
286 					ttyn);
287 				exit(1);
288 			}
289 			if (uugetty)
290 				(void)chown(lockfile, ttyowner, 0);
291 			(void)login_tty(i);
292 		}
293 	}
294 
295 	/* Start with default tty settings */
296 	if (tcgetattr(0, &tmode) < 0) {
297 		syslog(LOG_ERR, "%s: %m", ttyn);
298 		exit(1);
299 	}
300 	omode = tmode;
301 
302 	gettable("default", defent);
303 	gendefaults();
304 	if (argc > 1)
305 		tname = argv[1];
306 	for (;;) {
307 #if !defined(__minix)
308 		int off;
309 #endif /* !defined(__minix) */
310 
311 		rval = 0;
312 		gettable(tname, tabent);
313 		if (OPset || EPset || APset)
314 			APset++, OPset++, EPset++;
315 		setdefaults();
316 #if !defined(__minix)
317 		off = 0;
318 #endif /* !defined(__minix) */
319 		(void)tcflush(0, TCIOFLUSH);	/* clear out the crap */
320 #if !defined(__minix)
321 		(void)ioctl(0, FIONBIO, &off);	/* turn off non-blocking mode */
322 		(void)ioctl(0, FIOASYNC, &off);	/* ditto for async mode */
323 #endif /* !defined(__minix) */
324 
325 		if (IS)
326 			(void)cfsetispeed(&tmode, (speed_t)IS);
327 		else if (SP)
328 			(void)cfsetispeed(&tmode, (speed_t)SP);
329 		if (OS)
330 			(void)cfsetospeed(&tmode, (speed_t)OS);
331 		else if (SP)
332 			(void)cfsetospeed(&tmode, (speed_t)SP);
333 		setflags(0);
334 		setchars();
335 		if (tcsetattr(0, TCSANOW, &tmode) < 0) {
336 			syslog(LOG_ERR, "%s: %m", ttyn);
337 			exit(1);
338 		}
339 		if (AB) {
340 			tname = autobaud();
341 			continue;
342 		}
343 		if (PS) {
344 			tname = portselector();
345 			continue;
346 		}
347 		if (CS)
348 			clearscreen();
349 		if (CL && *CL)
350 			putpad(CL);
351 		edithost(HE);
352 
353 		/*
354 		 * If this is the first time through this, and an
355 		 * issue file has been given, then send it.
356 		 */
357 		if (first_time != 0 && IF != NULL) {
358 			char buf[_POSIX2_LINE_MAX];
359 			FILE *fp;
360 
361 			if ((fp = fopen(IF, "r")) != NULL) {
362 				while (fgets(buf, sizeof(buf) - 1, fp) != NULL)
363 					putf(buf);
364 				(void)fclose(fp);
365 			}
366 		}
367 		first_time = 0;
368 
369 		if (IM && *IM)
370 			putf(IM);
371 		oflush();
372 		if (sigsetjmp(timeout, 1)) {
373 			tmode.c_ispeed = tmode.c_ospeed = 0;
374 			(void)tcsetattr(0, TCSANOW, &tmode);
375 			exit(1);
376 		}
377 		if (TO) {
378 			(void)signal(SIGALRM, dingdong);
379 			(void)alarm((unsigned int)TO);
380 		}
381 		if (NN) {
382 			name[0] = '\0';
383 			lower = 1;
384 			upper = digit_or_punc = 0;
385 		} else if (AL) {
386 			const char *p = AL;
387 			char *q = name;
388 
389 			while (*p && q < &name[sizeof name - 1]) {
390 				if (isupper((unsigned char)*p))
391 					upper = 1;
392 				else if (islower((unsigned char)*p))
393 					lower = 1;
394 				else if (isdigit((unsigned char)*p))
395 					digit_or_punc = 1;
396 				*q++ = *p++;
397 			}
398 		} else if ((rval = getname()) == 2) {
399 			setflags(2);
400 			(void)execle(PP, "ppplogin", ttyn, (char *) 0, env);
401 			syslog(LOG_ERR, "%s: %m", PP);
402 			exit(1);
403 		}
404 
405 		if (rval || AL || NN) {
406 			int i;
407 
408 			oflush();
409 			(void)alarm(0);
410 			(void)signal(SIGALRM, SIG_DFL);
411 			if (name[0] == '-') {
412 				xputs("user names may not start with '-'.");
413 				continue;
414 			}
415 			if (!(upper || lower || digit_or_punc))
416 				continue;
417 			setflags(2);
418 			if (crmod) {
419 				tmode.c_iflag |= ICRNL;
420 				tmode.c_oflag |= ONLCR;
421 			}
422 #if XXX
423 			if (upper || UC)
424 				tmode.sg_flags |= LCASE;
425 			if (lower || LC)
426 				tmode.sg_flags &= ~LCASE;
427 #endif
428 			if (tcsetattr(0, TCSANOW, &tmode) < 0) {
429 				syslog(LOG_ERR, "%s: %m", ttyn);
430 				exit(1);
431 			}
432 			(void)signal(SIGINT, SIG_DFL);
433 			for (i = 0; envp[i] != NULL; i++)
434 				env[i] = envp[i];
435 			makeenv(&env[i]);
436 
437 			limit.rlim_max = RLIM_INFINITY;
438 			limit.rlim_cur = RLIM_INFINITY;
439 			(void)setrlimit(RLIMIT_CPU, &limit);
440 			if (NN)
441 				(void)execle(LO, "login", AL ? "-fp" : "-p",
442 				    NULL, env);
443 			else
444 				(void)execle(LO, "login", AL ? "-fp" : "-p",
445 				    "--", name, NULL, env);
446 			syslog(LOG_ERR, "%s: %m", LO);
447 			exit(1);
448 		}
449 		(void)alarm(0);
450 		(void)signal(SIGALRM, SIG_DFL);
451 		(void)signal(SIGINT, SIG_IGN);
452 		if (NX && *NX)
453 			tname = NX;
454 		if (uugetty)
455 			(void)unlink(lockfile);
456 	}
457 }
458 
459 static int
getname(void)460 getname(void)
461 {
462 	int c;
463 	char *np;
464 	unsigned char cs;
465 	int ppp_state, ppp_connection;
466 
467 	/*
468 	 * Interrupt may happen if we use CBREAK mode
469 	 */
470 	if (sigsetjmp(intrupt, 1)) {
471 		(void)signal(SIGINT, SIG_IGN);
472 		return (0);
473 	}
474 	(void)signal(SIGINT, interrupt);
475 	setflags(1);
476 	prompt();
477 	if (PF > 0) {
478 		oflush();
479 		(void)sleep((unsigned int)PF);
480 		PF = 0;
481 	}
482 	if (tcsetattr(0, TCSANOW, &tmode) < 0) {
483 		syslog(LOG_ERR, "%s: %m", ttyn);
484 		exit(1);
485 	}
486 	crmod = digit_or_punc = lower = upper = 0;
487 	ppp_state = ppp_connection = 0;
488 	np = name;
489 	for (;;) {
490 		oflush();
491 		if (read(STDIN_FILENO, &cs, 1) <= 0)
492 			exit(0);
493 		if ((c = cs&0177) == 0)
494 			return (0);
495 
496 		/*
497 		 * PPP detection state machine..
498 		 * Look for sequences:
499 		 * PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or
500 		 * PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC)
501 		 * See RFC1662.
502 		 * Derived from code from Michael Hancock <michaelh@cet.co.jp>
503 		 * and Erik 'PPP' Olson <eriko@wrq.com>
504 		 */
505 		if (PP && cs == PPP_FRAME) {
506 			ppp_state = 1;
507 		} else if (ppp_state == 1 && cs == PPP_STATION) {
508 			ppp_state = 2;
509 		} else if (ppp_state == 2 && cs == PPP_ESCAPE) {
510 			ppp_state = 3;
511 		} else if ((ppp_state == 2 && cs == PPP_CONTROL) ||
512 		    (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) {
513 			ppp_state = 4;
514 		} else if (ppp_state == 4 && cs == PPP_LCP_HI) {
515 			ppp_state = 5;
516 		} else if (ppp_state == 5 && cs == PPP_LCP_LOW) {
517 			ppp_connection = 1;
518 			break;
519 		} else {
520 			ppp_state = 0;
521 		}
522 
523 		if (c == EOT)
524 			exit(1);
525 		if (c == '\r' || c == '\n' ||
526 		    np >= &name[LOGIN_NAME_MAX - 1]) {
527 			*np = '\0';
528 			putf("\r\n");
529 			break;
530 		}
531 		if (islower(c))
532 			lower = 1;
533 		else if (isupper(c))
534 			upper = 1;
535 		else if (c == ERASE || c == '#' || c == '\b') {
536 			if (np > name) {
537 				np--;
538 				if (cfgetospeed(&tmode) >= 1200)
539 					xputs("\b \b");
540 				else
541 					putchr(cs);
542 			}
543 			continue;
544 		} else if (c == KILL || c == '@') {
545 			putchr(cs);
546 			putchr('\r');
547 			if (cfgetospeed(&tmode) < 1200)
548 				putchr('\n');
549 			/* this is the way they do it down under ... */
550 			else if (np > name)
551 				xputs(
552 				    "                                     \r");
553 			prompt();
554 			np = name;
555 			continue;
556 		} else if (isdigit(c) || c == '_')
557 			digit_or_punc = 1;
558 		if (IG && (c <= ' ' || c > 0176))
559 			continue;
560 		*np++ = c;
561 		putchr(cs);
562 
563 		/*
564 		 * An MS-Windows direct connect PPP "client" won't send its
565 		 * first PPP packet until we respond to its "CLIENT" poll
566 		 * with a CRLF sequence.  We cater to yet another broken
567 		 * implementation of a previously-standard protocol...
568 		 */
569 		*np = '\0';
570 		if (strstr(name, "CLIENT"))
571 			putf("\r\n");
572 	}
573 	(void)signal(SIGINT, SIG_IGN);
574 	*np = 0;
575 	if (c == '\r')
576 		crmod = 1;
577 	if ((upper && !lower && !LC) || UC)
578 		for (np = name; *np; np++)
579 			*np = tolower((unsigned char)*np);
580 	return (1 + ppp_connection);
581 }
582 
583 static void
xputs(const char * s)584 xputs(const char *s)
585 {
586 	while (*s)
587 		putchr(*s++);
588 }
589 
590 char	outbuf[OBUFSIZ];
591 size_t	obufcnt = 0;
592 
593 static int
putchr(int cc)594 putchr(int cc)
595 {
596 	unsigned char c;
597 
598 	c = cc;
599 	if (!NP) {
600 		c |= partab[c&0177] & 0200;
601 		if (OP)
602 			c ^= 0200;
603 	}
604 	if (!UB) {
605 		outbuf[obufcnt++] = c;
606 		if (obufcnt >= OBUFSIZ)
607 			oflush();
608 		return 1;
609 	}
610 	return write(STDOUT_FILENO, &c, 1);
611 }
612 
613 static void
oflush(void)614 oflush(void)
615 {
616 	if (obufcnt)
617 		(void)write(STDOUT_FILENO, outbuf, obufcnt);
618 	obufcnt = 0;
619 }
620 
621 static void
prompt(void)622 prompt(void)
623 {
624 
625 	putf(LM);
626 	if (CO)
627 		putchr('\n');
628 }
629 
630 static void
putf(const char * cp)631 putf(const char *cp)
632 {
633 	time_t t;
634 	char *slash, db[100];
635 
636 	while (*cp) {
637 		if (*cp != '%') {
638 			putchr(*cp++);
639 			continue;
640 		}
641 		switch (*++cp) {
642 
643 		case 't':
644 			if ((slash = strstr(ttyn, "/pts/")) == NULL)
645 				slash = strrchr(ttyn, '/');
646 			if (slash == NULL)
647 				xputs(ttyn);
648 			else
649 				xputs(&slash[1]);
650 			break;
651 
652 		case 'h':
653 			xputs(editedhost);
654 			break;
655 
656 		case 'd':
657 			(void)time(&t);
658 			(void)strftime(db, sizeof(db),
659 			    "%l:%M%p on %A, %d %B %Y", localtime(&t));
660 			xputs(db);
661 			break;
662 
663 		case 's':
664 			xputs(kerninfo.sysname);
665 			break;
666 
667 		case 'm':
668 			xputs(kerninfo.machine);
669 			break;
670 
671 		case 'r':
672 			xputs(kerninfo.release);
673 			break;
674 
675 		case 'v':
676 			xputs(kerninfo.version);
677 			break;
678 
679 		case '%':
680 			putchr('%');
681 			break;
682 		}
683 		if (*cp)
684 			cp++;
685 	}
686 }
687 
688 static void
clearscreen(void)689 clearscreen(void)
690 {
691 	struct ttyent *typ;
692 	int err;
693 
694 	if (rawttyn == NULL)
695 		return;
696 
697 	typ = getttynam(rawttyn);
698 
699 	if ((typ == NULL) || (typ->ty_type == NULL) ||
700 	    (typ->ty_type[0] == 0))
701 		return;
702 
703 	if (setupterm(typ->ty_type, 0, &err) == ERR)
704 		return;
705 
706 	if (clear_screen)
707 		putpad(clear_screen);
708 
709 	del_curterm(cur_term);
710 	cur_term = NULL;
711 }
712