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