xref: /netbsd-src/libexec/getty/main.c (revision e5548b402ae4c44fb816de42c7bba9581ce23ef5)
1 /*	$NetBSD: main.c,v 1.49 2005/09/10 21:29:36 elad 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.49 2005/09/10 21:29:36 elad 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 <fcntl.h>
59 #include <pwd.h>
60 #include <setjmp.h>
61 #include <signal.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #include <syslog.h>
65 #include <time.h>
66 #include <unistd.h>
67 #include <util.h>
68 #include <limits.h>
69 #include <ttyent.h>
70 #include <termcap.h>
71 
72 #include "gettytab.h"
73 #include "pathnames.h"
74 #include "extern.h"
75 
76 extern char **environ;
77 extern char editedhost[];
78 
79 /*
80  * Set the amount of running time that getty should accumulate
81  * before deciding that something is wrong and exit.
82  */
83 #define GETTY_TIMEOUT	60 /* seconds */
84 
85 /* defines for auto detection of incoming PPP calls (->PAP/CHAP) */
86 
87 #define PPP_FRAME           0x7e  /* PPP Framing character */
88 #define PPP_STATION         0xff  /* "All Station" character */
89 #define PPP_ESCAPE          0x7d  /* Escape Character */
90 #define PPP_CONTROL         0x03  /* PPP Control Field */
91 #define PPP_CONTROL_ESCAPED 0x23  /* PPP Control Field, escaped */
92 #define PPP_LCP_HI          0xc0  /* LCP protocol - high byte */
93 #define PPP_LCP_LOW         0x21  /* LCP protocol - low byte */
94 
95 struct termios tmode, omode;
96 
97 int crmod, digit, lower, upper;
98 
99 char	hostname[MAXHOSTNAMELEN + 1];
100 struct	utsname kerninfo;
101 char	name[LOGIN_NAME_MAX];
102 char	dev[] = _PATH_DEV;
103 char	ttyn[32];
104 char	lockfile[512];
105 uid_t	ttyowner;
106 char	*rawttyn;
107 
108 #define	OBUFSIZ		128
109 #define	TABBUFSIZ	512
110 
111 char	defent[TABBUFSIZ];
112 char	tabent[TABBUFSIZ];
113 
114 char	*env[128];
115 
116 const char partab[] = {
117 	0001,0201,0201,0001,0201,0001,0001,0201,
118 	0202,0004,0003,0205,0005,0206,0201,0001,
119 	0201,0001,0001,0201,0001,0201,0201,0001,
120 	0001,0201,0201,0001,0201,0001,0001,0201,
121 	0200,0000,0000,0200,0000,0200,0200,0000,
122 	0000,0200,0200,0000,0200,0000,0000,0200,
123 	0000,0200,0200,0000,0200,0000,0000,0200,
124 	0200,0000,0000,0200,0000,0200,0200,0000,
125 	0200,0000,0000,0200,0000,0200,0200,0000,
126 	0000,0200,0200,0000,0200,0000,0000,0200,
127 	0000,0200,0200,0000,0200,0000,0000,0200,
128 	0200,0000,0000,0200,0000,0200,0200,0000,
129 	0000,0200,0200,0000,0200,0000,0000,0200,
130 	0200,0000,0000,0200,0000,0200,0200,0000,
131 	0200,0000,0000,0200,0000,0200,0200,0000,
132 	0000,0200,0200,0000,0200,0000,0000,0201
133 };
134 
135 #define	ERASE	tmode.c_cc[VERASE]
136 #define	KILL	tmode.c_cc[VKILL]
137 #define	EOT	tmode.c_cc[VEOF]
138 
139 static void	clearscreen(void);
140 
141 jmp_buf timeout;
142 
143 static void
144 dingdong(int signo)
145 {
146 
147 	alarm(0);
148 	signal(SIGALRM, SIG_DFL);
149 	longjmp(timeout, 1);
150 }
151 
152 jmp_buf	intrupt;
153 
154 static void
155 interrupt(int signo)
156 {
157 
158 	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 timeoverrun(int signo)
167 {
168 
169 	syslog(LOG_ERR, "getty exiting due to excessive running time");
170 	exit(1);
171 }
172 
173 int		main(int, char *[]);
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[])
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 #ifdef __GNUC__
193 	(void)&tname;		/* XXX gcc -Wall */
194 #endif
195 
196 	signal(SIGINT, SIG_IGN);
197 /*
198 	signal(SIGQUIT, SIG_DFL);
199 */
200 	openlog("getty", LOG_PID, LOG_AUTH);
201 	gethostname(hostname, sizeof(hostname));
202 	hostname[sizeof(hostname) - 1] = '\0';
203 	if (hostname[0] == '\0')
204 		strlcpy(hostname, "Amnesiac", sizeof(hostname));
205 	uname(&kerninfo);
206 
207 	progname = getprogname();
208 	if (progname[0] == 'u' && progname[1] == 'u')
209 		uugetty = 1;
210 
211 	/*
212 	 * Find id of uucp login (if present) so we can chown tty properly.
213 	 */
214 	if (uugetty && (pw = getpwnam("uucp")))
215 		ttyowner = pw->pw_uid;
216 	else
217 		ttyowner = 0;
218 
219 	/*
220 	 * Limit running time to deal with broken or dead lines.
221 	 */
222 	(void)signal(SIGXCPU, timeoverrun);
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 	    strlcpy(ttyn, ttyname(0), sizeof(ttyn));
236 	}
237 	else {
238 	    int i;
239 
240 	    rawttyn = argv[2];
241 	    strlcpy(ttyn, dev, sizeof(ttyn));
242 	    strlcat(ttyn, argv[2], sizeof(ttyn));
243 
244 	    if (uugetty)  {
245 		chown(ttyn, ttyowner, 0);
246 		strlcpy(lockfile, _PATH_LOCK, sizeof(lockfile));
247 		strlcat(lockfile, argv[2], sizeof(lockfile));
248 		/* wait for lockfiles to go away before we try to open */
249 		if ( pidlock(lockfile, 0, 0, 0) != 0 )  {
250 		    syslog(LOG_ERR, "%s: can't create lockfile", ttyn);
251 		    exit(1);
252 		}
253 		unlink(lockfile);
254 	    }
255 	    if (strcmp(argv[0], "+") != 0) {
256 		chown(ttyn, ttyowner, 0);
257 		chmod(ttyn, 0600);
258 		revoke(ttyn);
259 		if (ttyaction(ttyn, "getty", "root"))
260 			syslog(LOG_WARNING, "%s: ttyaction failed", ttyn);
261 		/*
262 		 * Delay the open so DTR stays down long enough to be detected.
263 		 */
264 		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 			sleep(60);
274 		}
275 		if (uugetty && pidlock(lockfile, 0, 0, 0) != 0)  {
276 			syslog(LOG_ERR, "%s: can't create lockfile", ttyn);
277 			exit(1);
278 		}
279 		if (uugetty)
280 			(void) chown(lockfile, ttyowner, 0);
281 		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 		ioctl(0, FIONBIO, &off);	/* turn off non-blocking mode */
308 		ioctl(0, FIOASYNC, &off);	/* ditto for async mode */
309 
310 		if (IS)
311 			cfsetispeed(&tmode, IS);
312 		else if (SP)
313 			cfsetispeed(&tmode, SP);
314 		if (OS)
315 			cfsetospeed(&tmode, OS);
316 		else if (SP)
317 			cfsetospeed(&tmode, 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 *fd;
345 
346 			if ((fd = fopen(IF, "r")) != NULL) {
347 				while (fgets(buf, sizeof(buf) - 1, fd) != NULL)
348 					putf(buf);
349 				fclose(fd);
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 			signal(SIGALRM, dingdong);
364 			alarm(TO);
365 		}
366 		if (NN) {
367 			name[0] = '\0';
368 			lower = 1;
369 			upper = digit = 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++;
381 				*q++ = *p++;
382 			}
383 		} else if ((rval = getname()) == 2) {
384 		        execle(PP, "ppplogin", ttyn, (char *) 0, env);
385 		        syslog(LOG_ERR, "%s: %m", PP);
386 		        exit(1);
387 		}
388 
389 		if (rval || AL || NN) {
390 			int i;
391 
392 			oflush();
393 			alarm(0);
394 			signal(SIGALRM, SIG_DFL);
395 			if (name[0] == '-') {
396 				xputs("user names may not start with '-'.");
397 				continue;
398 			}
399 			if (!(upper || lower || digit))
400 				continue;
401 			setflags(2);
402 			if (crmod) {
403 				tmode.c_iflag |= ICRNL;
404 				tmode.c_oflag |= ONLCR;
405 			}
406 #if XXX
407 			if (upper || UC)
408 				tmode.sg_flags |= LCASE;
409 			if (lower || LC)
410 				tmode.sg_flags &= ~LCASE;
411 #endif
412 			if (tcsetattr(0, TCSANOW, &tmode) < 0) {
413 				syslog(LOG_ERR, "%s: %m", ttyn);
414 				exit(1);
415 			}
416 			signal(SIGINT, SIG_DFL);
417 			for (i = 0; environ[i] != (char *)0; i++)
418 				env[i] = environ[i];
419 			makeenv(&env[i]);
420 
421 			limit.rlim_max = RLIM_INFINITY;
422 			limit.rlim_cur = RLIM_INFINITY;
423 			(void)setrlimit(RLIMIT_CPU, &limit);
424 			if (NN)
425 				execle(LO, "login", AL ? "-fp" : "-p",
426 				    NULL, env);
427 			else
428 				execle(LO, "login", AL ? "-fp" : "-p",
429 				    "--", name, NULL, env);
430 			syslog(LOG_ERR, "%s: %m", LO);
431 			exit(1);
432 		}
433 		alarm(0);
434 		signal(SIGALRM, SIG_DFL);
435 		signal(SIGINT, SIG_IGN);
436 		if (NX && *NX)
437 			tname = NX;
438 		if (uugetty)
439 			unlink(lockfile);
440 	}
441 }
442 
443 static int
444 getname(void)
445 {
446 	int c;
447 	char *np;
448 	unsigned char cs;
449 	int ppp_state, ppp_connection;
450 
451 	/*
452 	 * Interrupt may happen if we use CBREAK mode
453 	 */
454 	if (setjmp(intrupt)) {
455 		signal(SIGINT, SIG_IGN);
456 		return (0);
457 	}
458 	signal(SIGINT, interrupt);
459 	setflags(1);
460 	prompt();
461 	if (PF > 0) {
462 		oflush();
463 		sleep(PF);
464 		PF = 0;
465 	}
466 	if (tcsetattr(0, TCSANOW, &tmode) < 0) {
467 		syslog(LOG_ERR, "%s: %m", ttyn);
468 		exit(1);
469 	}
470 	crmod = digit = lower = upper = 0;
471         ppp_state = ppp_connection = 0;
472 	np = name;
473 	for (;;) {
474 		oflush();
475 		if (read(STDIN_FILENO, &cs, 1) <= 0)
476 			exit(0);
477 		if ((c = cs&0177) == 0)
478 			return (0);
479 
480 		/*
481 		 * PPP detection state machine..
482 		 * Look for sequences:
483 		 * PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or
484 		 * PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC)
485 		 * See RFC1662.
486 		 * Derived from code from Michael Hancock <michaelh@cet.co.jp>
487 		 * and Erik 'PPP' Olson <eriko@wrq.com>
488 		 */
489 		if (PP && cs == PPP_FRAME) {
490 			ppp_state = 1;
491 		} else if (ppp_state == 1 && cs == PPP_STATION) {
492 			ppp_state = 2;
493 		} else if (ppp_state == 2 && cs == PPP_ESCAPE) {
494 			ppp_state = 3;
495 		} else if ((ppp_state == 2 && cs == PPP_CONTROL) ||
496 		    (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) {
497 			ppp_state = 4;
498 		} else if (ppp_state == 4 && cs == PPP_LCP_HI) {
499 			ppp_state = 5;
500 		} else if (ppp_state == 5 && cs == PPP_LCP_LOW) {
501 			ppp_connection = 1;
502 			break;
503 		} else {
504 			ppp_state = 0;
505 		}
506 
507 		if (c == EOT)
508 			exit(1);
509 		if (c == '\r' || c == '\n' ||
510 		    np >= &name[LOGIN_NAME_MAX - 1]) {
511 			*np = '\0';
512 			putf("\r\n");
513 			break;
514 		}
515 		if (islower(c))
516 			lower = 1;
517 		else if (isupper(c))
518 			upper = 1;
519 		else if (c == ERASE || c == '#' || c == '\b') {
520 			if (np > name) {
521 				np--;
522 				if (cfgetospeed(&tmode) >= 1200)
523 					xputs("\b \b");
524 				else
525 					putchr(cs);
526 			}
527 			continue;
528 		} else if (c == KILL || c == '@') {
529 			putchr(cs);
530 			putchr('\r');
531 			if (cfgetospeed(&tmode) < 1200)
532 				putchr('\n');
533 			/* this is the way they do it down under ... */
534 			else if (np > name)
535 				xputs(
536 				    "                                     \r");
537 			prompt();
538 			np = name;
539 			continue;
540 		} else if (isdigit(c))
541 			digit++;
542 		if (IG && (c <= ' ' || c > 0176))
543 			continue;
544 		*np++ = c;
545 		putchr(cs);
546 
547 		/*
548 		 * An MS-Windows direct connect PPP "client" won't send its
549 		 * first PPP packet until we respond to its "CLIENT" poll
550 		 * with a CRLF sequence.  We cater to yet another broken
551 		 * implementation of a previously-standard protocol...
552 		 */
553 		*np = '\0';
554 		if (strstr(name, "CLIENT"))
555 		       putf("\r\n");
556 	}
557 	signal(SIGINT, SIG_IGN);
558 	*np = 0;
559 	if (c == '\r')
560 		crmod = 1;
561 	if ((upper && !lower && !LC) || UC)
562 		for (np = name; *np; np++)
563 			*np = tolower((unsigned char)*np);
564 	return (1 + ppp_connection);
565 }
566 
567 static void
568 putpad(const char *s)
569 {
570 	int pad = 0;
571 	speed_t ospeed = cfgetospeed(&tmode);
572 
573 	if (isdigit((unsigned char)*s)) {
574 		while (isdigit((unsigned char)*s)) {
575 			pad *= 10;
576 			pad += *s++ - '0';
577 		}
578 		pad *= 10;
579 		if (*s == '.' && isdigit((unsigned char)s[1])) {
580 			pad += s[1] - '0';
581 			s += 2;
582 		}
583 	}
584 
585 	xputs(s);
586 	/*
587 	 * If no delay needed, or output speed is
588 	 * not comprehensible, then don't try to delay.
589 	 */
590 	if (pad == 0 || ospeed <= 0)
591 		return;
592 
593 	/*
594 	 * Round up by a half a character frame, and then do the delay.
595 	 * Too bad there are no user program accessible programmed delays.
596 	 * Transmitting pad characters slows many terminals down and also
597 	 * loads the system.
598 	 */
599 	pad = (pad * ospeed + 50000) / 100000;
600 	while (pad--)
601 		putchr(*PC);
602 }
603 
604 static void
605 xputs(const char *s)
606 {
607 	while (*s)
608 		putchr(*s++);
609 }
610 
611 char	outbuf[OBUFSIZ];
612 int	obufcnt = 0;
613 
614 static void
615 putchr(int cc)
616 {
617 	char c;
618 
619 	c = cc;
620 	if (!NP) {
621 		c |= partab[c&0177] & 0200;
622 		if (OP)
623 			c ^= 0200;
624 	}
625 	if (!UB) {
626 		outbuf[obufcnt++] = c;
627 		if (obufcnt >= OBUFSIZ)
628 			oflush();
629 	} else
630 		write(STDOUT_FILENO, &c, 1);
631 }
632 
633 static void
634 oflush(void)
635 {
636 	if (obufcnt)
637 		write(STDOUT_FILENO, outbuf, obufcnt);
638 	obufcnt = 0;
639 }
640 
641 static void
642 prompt(void)
643 {
644 
645 	putf(LM);
646 	if (CO)
647 		putchr('\n');
648 }
649 
650 static void
651 putf(const char *cp)
652 {
653 	time_t t;
654 	char *slash, db[100];
655 
656 	while (*cp) {
657 		if (*cp != '%') {
658 			putchr(*cp++);
659 			continue;
660 		}
661 		switch (*++cp) {
662 
663 		case 't':
664 			if ((slash = strstr(ttyn, "/pts/")) == NULL)
665 				slash = strrchr(ttyn, '/');
666 			if (slash == NULL)
667 				xputs(ttyn);
668 			else
669 				xputs(&slash[1]);
670 			break;
671 
672 		case 'h':
673 			xputs(editedhost);
674 			break;
675 
676 		case 'd':
677 			(void)time(&t);
678 			(void)strftime(db, sizeof(db),
679 			    /* SCCS eats %M% */
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 	struct tinfo *tinfo;
714 	char *cs;
715 
716 	if (rawttyn == NULL)
717 		return;
718 
719 	typ = getttynam(rawttyn);
720 
721 	if ((typ == NULL) || (typ->ty_type == NULL) ||
722 	    (typ->ty_type[0] == 0))
723 		return;
724 
725 	if (t_getent(&tinfo, typ->ty_type) <= 0)
726 		return;
727 
728 	cs = t_agetstr(tinfo, "cl");
729 	if (cs == NULL)
730 		return;
731 
732 	putpad(cs);
733 }
734