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