xref: /openbsd-src/libexec/getty/main.c (revision 4538572b6b255b20e2c8d3fc8d9311d6473559cb)
1*4538572bSbluhm /*	$OpenBSD: main.c,v 1.56 2024/07/19 15:28:51 bluhm Exp $	*/
25d36dfa4Sniklas 
3df930be7Sderaadt /*-
4df930be7Sderaadt  * Copyright (c) 1980, 1993
5df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
6df930be7Sderaadt  *
7df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
8df930be7Sderaadt  * modification, are permitted provided that the following conditions
9df930be7Sderaadt  * are met:
10df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
11df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
12df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
13df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
14df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
15e33d3bd3Smillert  * 3. Neither the name of the University nor the names of its contributors
16df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
17df930be7Sderaadt  *    without specific prior written permission.
18df930be7Sderaadt  *
19df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29df930be7Sderaadt  * SUCH DAMAGE.
30df930be7Sderaadt  */
31df930be7Sderaadt 
32df930be7Sderaadt #include <sys/stat.h>
33df930be7Sderaadt #include <termios.h>
34df930be7Sderaadt #include <sys/ioctl.h>
35df930be7Sderaadt #include <sys/resource.h>
36df930be7Sderaadt #include <sys/utsname.h>
37df930be7Sderaadt #include <errno.h>
38df930be7Sderaadt #include <signal.h>
39df930be7Sderaadt #include <fcntl.h>
40df930be7Sderaadt #include <time.h>
41df930be7Sderaadt #include <ctype.h>
42df930be7Sderaadt #include <stdlib.h>
43df930be7Sderaadt #include <string.h>
44df930be7Sderaadt #include <syslog.h>
45ae56b8b7Sderaadt #include <stdio.h>
46df930be7Sderaadt #include <unistd.h>
4752dc30e1Sderaadt #include <limits.h>
480abcd724Sderaadt #include <util.h>
49df930be7Sderaadt 
50df930be7Sderaadt #include "gettytab.h"
51df930be7Sderaadt #include "pathnames.h"
52df930be7Sderaadt #include "extern.h"
53df930be7Sderaadt 
54df930be7Sderaadt /*
55df930be7Sderaadt  * Set the amount of running time that getty should accumulate
56df930be7Sderaadt  * before deciding that something is wrong and exit.
57df930be7Sderaadt  */
58df930be7Sderaadt #define GETTY_TIMEOUT	60 /* seconds */
59df930be7Sderaadt 
60df930be7Sderaadt struct termios tmode, omode;
61df930be7Sderaadt 
62df930be7Sderaadt int crmod, digit, lower, upper;
63df930be7Sderaadt 
6452dc30e1Sderaadt char	hostname[HOST_NAME_MAX+1];
6530d77a25Stedu char	globalhostname[HOST_NAME_MAX+1];
66df930be7Sderaadt struct	utsname kerninfo;
6752dc30e1Sderaadt char	name[LOGIN_NAME_MAX];
68df930be7Sderaadt char	ttyn[32];
6974637cb2Sderaadt char	*portselector(void);
70df930be7Sderaadt 
71df930be7Sderaadt #define	OBUFSIZ		128
72df930be7Sderaadt #define	TABBUFSIZ	512
73df930be7Sderaadt 
74df930be7Sderaadt char	defent[TABBUFSIZ];
75df930be7Sderaadt char	tabent[TABBUFSIZ];
76bf6d4de2Sderaadt char	saveLO[FILENAME_MAX];
77df930be7Sderaadt 
78df930be7Sderaadt char	*env[128];
79df930be7Sderaadt 
80df930be7Sderaadt char partab[] = {
81df930be7Sderaadt 	0001,0201,0201,0001,0201,0001,0001,0201,
82df930be7Sderaadt 	0202,0004,0003,0205,0005,0206,0201,0001,
83df930be7Sderaadt 	0201,0001,0001,0201,0001,0201,0201,0001,
84df930be7Sderaadt 	0001,0201,0201,0001,0201,0001,0001,0201,
85df930be7Sderaadt 	0200,0000,0000,0200,0000,0200,0200,0000,
86df930be7Sderaadt 	0000,0200,0200,0000,0200,0000,0000,0200,
87df930be7Sderaadt 	0000,0200,0200,0000,0200,0000,0000,0200,
88df930be7Sderaadt 	0200,0000,0000,0200,0000,0200,0200,0000,
89df930be7Sderaadt 	0200,0000,0000,0200,0000,0200,0200,0000,
90df930be7Sderaadt 	0000,0200,0200,0000,0200,0000,0000,0200,
91df930be7Sderaadt 	0000,0200,0200,0000,0200,0000,0000,0200,
92df930be7Sderaadt 	0200,0000,0000,0200,0000,0200,0200,0000,
93df930be7Sderaadt 	0000,0200,0200,0000,0200,0000,0000,0200,
94df930be7Sderaadt 	0200,0000,0000,0200,0000,0200,0200,0000,
95df930be7Sderaadt 	0200,0000,0000,0200,0000,0200,0200,0000,
96df930be7Sderaadt 	0000,0200,0200,0000,0200,0000,0000,0201
97df930be7Sderaadt };
98df930be7Sderaadt 
99df930be7Sderaadt #define	ERASE	tmode.c_cc[VERASE]
100df930be7Sderaadt #define	KILL	tmode.c_cc[VKILL]
101df930be7Sderaadt #define	EOT	tmode.c_cc[VEOF]
102df930be7Sderaadt 
103df930be7Sderaadt static void
1045b48e80aSderaadt dingdong(int signo)
105df930be7Sderaadt {
10652113b74Sderaadt 	tmode.c_ispeed = tmode.c_ospeed = 0;
10752113b74Sderaadt 	(void)tcsetattr(0, TCSANOW, &tmode);
10852113b74Sderaadt 	_exit(1);
109df930be7Sderaadt }
110df930be7Sderaadt 
11152113b74Sderaadt volatile sig_atomic_t interrupt_flag;
112df930be7Sderaadt 
113df930be7Sderaadt static void
1145b48e80aSderaadt interrupt(int signo)
115df930be7Sderaadt {
11652113b74Sderaadt 	int save_errno = errno;
117df930be7Sderaadt 
11852113b74Sderaadt 	interrupt_flag = 1;
119df930be7Sderaadt 	signal(SIGINT, interrupt);
12052113b74Sderaadt 	errno = save_errno;
121df930be7Sderaadt }
122df930be7Sderaadt 
123df930be7Sderaadt /*
124df930be7Sderaadt  * Action to take when getty is running too long.
125df930be7Sderaadt  */
126aa31cba2Sderaadt static void
1275b48e80aSderaadt timeoverrun(int signo)
128df930be7Sderaadt {
12952113b74Sderaadt 	struct syslog_data sdata = SYSLOG_DATA_INIT;
13052113b74Sderaadt 
13152113b74Sderaadt 	syslog_r(LOG_ERR, &sdata,
13252113b74Sderaadt 	    "getty exiting due to excessive running time");
133af4f388aSderaadt 	_exit(1);
134df930be7Sderaadt }
135df930be7Sderaadt 
136c72b5b24Smillert static int	getname(void);
137c72b5b24Smillert static void	oflush(void);
138c72b5b24Smillert static void	prompt(void);
139c72b5b24Smillert static void	putchr(int);
140c72b5b24Smillert static void	putf(char *);
141c72b5b24Smillert static void	putpad(char *);
142c72b5b24Smillert static void	xputs(char *);
143df930be7Sderaadt 
144df930be7Sderaadt int
1455b48e80aSderaadt main(int argc, char *argv[])
146df930be7Sderaadt {
147df930be7Sderaadt 	extern char **environ;
148df930be7Sderaadt 	char *tname;
149df930be7Sderaadt 	int repcnt = 0, failopenlogged = 0;
150df930be7Sderaadt 	struct rlimit limit;
15154eda240Stedu 	int off = 0;
152df930be7Sderaadt 
153df930be7Sderaadt 	signal(SIGINT, SIG_IGN);
154df930be7Sderaadt /*
155df930be7Sderaadt 	signal(SIGQUIT, SIG_DFL);
156df930be7Sderaadt */
157df930be7Sderaadt 	openlog("getty", LOG_ODELAY|LOG_CONS|LOG_PID, LOG_AUTH);
158df930be7Sderaadt 	gethostname(hostname, sizeof(hostname));
159df930be7Sderaadt 	if (hostname[0] == '\0')
16048f8891fSderaadt 		strlcpy(hostname, "Amnesiac", sizeof hostname);
161df930be7Sderaadt 	uname(&kerninfo);
162df930be7Sderaadt 
163df930be7Sderaadt 	/*
164df930be7Sderaadt 	 * Limit running time to deal with broken or dead lines.
165df930be7Sderaadt 	 */
166df930be7Sderaadt 	(void)signal(SIGXCPU, timeoverrun);
167df930be7Sderaadt 	limit.rlim_max = RLIM_INFINITY;
168df930be7Sderaadt 	limit.rlim_cur = GETTY_TIMEOUT;
169df930be7Sderaadt 	(void)setrlimit(RLIMIT_CPU, &limit);
170df930be7Sderaadt 
171ae7aa16aSderaadt 	ioctl(0, FIOASYNC, &off);	/* turn off async mode */
172ae7aa16aSderaadt 
1739542d0dfSflorian 	tname = "default";
1749542d0dfSflorian 
175*4538572bSbluhm 	if (unveil(_PATH_GETTYTAB, "r") == -1 ||
176*4538572bSbluhm 	    unveil(_PATH_GETTYTAB ".db", "r") == -1) {
177239b4933Sderaadt 		syslog(LOG_ERR, "%s: %m", tname);
178239b4933Sderaadt 		exit(1);
179239b4933Sderaadt 	}
180239b4933Sderaadt 	if (unveil("/dev", "rw") == -1) {
181239b4933Sderaadt 		syslog(LOG_ERR, "%s: %m", tname);
182239b4933Sderaadt 		exit(1);
183239b4933Sderaadt 	}
184bf6d4de2Sderaadt 	if (unveil(_PATH_GETTY, "x") == -1) {
185bf6d4de2Sderaadt 		syslog(LOG_ERR, "%s: %m", tname);
186bf6d4de2Sderaadt 		exit(1);
187bf6d4de2Sderaadt 	}
188bf6d4de2Sderaadt 
189bf6d4de2Sderaadt 	gettable("default", defent);
190bf6d4de2Sderaadt 	gendefaults();
191bf6d4de2Sderaadt 	if (argc > 1)
192bf6d4de2Sderaadt 		tname = argv[1];
193bf6d4de2Sderaadt 	gettable(tname, tabent);
194bf6d4de2Sderaadt 	if (LO == NULL)
195bf6d4de2Sderaadt 		LO = _PATH_LOGIN;
196bf6d4de2Sderaadt 	if (unveil(LO, "x") == -1) {
197bf6d4de2Sderaadt 		syslog(LOG_ERR, "%s: %m", tname);
198bf6d4de2Sderaadt 		exit(1);
199bf6d4de2Sderaadt 	}
2009e74ecfaSrob 	if (unveil(NULL, NULL) == -1) {
2019e74ecfaSrob 		syslog(LOG_ERR, "%s: %m", tname);
2029e74ecfaSrob 		exit(1);
2039e74ecfaSrob 	}
204bf6d4de2Sderaadt 	strlcpy(saveLO, LO, sizeof saveLO);
205239b4933Sderaadt 
206df930be7Sderaadt 	/*
207df930be7Sderaadt 	 * The following is a work around for vhangup interactions
208df930be7Sderaadt 	 * which cause great problems getting window systems started.
209df930be7Sderaadt 	 * If the tty line is "-", we do the old style getty presuming
210df930be7Sderaadt 	 * that the file descriptors are already set up for us.
211df930be7Sderaadt 	 * J. Gettys - MIT Project Athena.
212df930be7Sderaadt 	 */
213d0329355Sderaadt 	if (argc <= 2 || strcmp(argv[2], "-") == 0) {
2142acff669Sderaadt 		if (pledge("stdio rpath proc exec tty", NULL) == -1) {
2152acff669Sderaadt 			syslog(LOG_ERR, "pledge: %m");
2162acff669Sderaadt 			exit(1);
2172acff669Sderaadt 		}
2182acff669Sderaadt 
21965746b0cSmillert 		if ((tname = ttyname(0)) == NULL) {
22065746b0cSmillert 			syslog(LOG_ERR, "stdin: %m");
22165746b0cSmillert 			exit(1);
22265746b0cSmillert 		}
22365746b0cSmillert 		if (strlcpy(ttyn, tname, sizeof(ttyn)) >= sizeof(ttyn)) {
22465746b0cSmillert 			errno = ENAMETOOLONG;
22565746b0cSmillert 			syslog(LOG_ERR, "%s: %m", tname);
22665746b0cSmillert 			exit(1);
22765746b0cSmillert 		}
228d0329355Sderaadt 	} else {
229df930be7Sderaadt 		int i;
230df930be7Sderaadt 
2312d313e67Sderaadt 		snprintf(ttyn, sizeof ttyn, "%s%s", _PATH_DEV, argv[2]);
232df930be7Sderaadt 		if (strcmp(argv[0], "+") != 0) {
233df930be7Sderaadt 			chown(ttyn, 0, 0);
234df930be7Sderaadt 			chmod(ttyn, 0600);
235df930be7Sderaadt 			revoke(ttyn);
236df930be7Sderaadt 			/*
237df930be7Sderaadt 			 * Delay the open so DTR stays down long enough to be detected.
238df930be7Sderaadt 			 */
239df930be7Sderaadt 			sleep(2);
240df930be7Sderaadt 			while ((i = open(ttyn, O_RDWR)) == -1) {
241df930be7Sderaadt 				if ((repcnt % 10 == 0) &&
242df930be7Sderaadt 				    (errno != ENXIO || !failopenlogged)) {
243df930be7Sderaadt 					syslog(LOG_ERR, "%s: %m", ttyn);
244df930be7Sderaadt 					closelog();
245df930be7Sderaadt 					failopenlogged = 1;
246df930be7Sderaadt 				}
247df930be7Sderaadt 				repcnt++;
248df930be7Sderaadt 				sleep(60);
249df930be7Sderaadt 			}
250df930be7Sderaadt 			login_tty(i);
251df930be7Sderaadt 		}
252df930be7Sderaadt 	}
253cfbffc8cSderaadt 
254ae7aa16aSderaadt 	if (pledge("stdio rpath proc exec tty", NULL) == -1) {
255cfbffc8cSderaadt 		syslog(LOG_ERR, "pledge: %m");
256cfbffc8cSderaadt 		exit(1);
257cfbffc8cSderaadt 	}
258df930be7Sderaadt 
259df930be7Sderaadt 	/* Start with default tty settings */
260df69c215Sderaadt 	if (tcgetattr(0, &tmode) == -1) {
261df930be7Sderaadt 		syslog(LOG_ERR, "%s: %m", ttyn);
262df930be7Sderaadt 		exit(1);
263df930be7Sderaadt 	}
264df930be7Sderaadt 	omode = tmode;
265df930be7Sderaadt 
266df930be7Sderaadt 	for (;;) {
267df930be7Sderaadt 		gettable(tname, tabent);
268bf6d4de2Sderaadt 		if (strcmp(LO, saveLO) != 0) {
269bf6d4de2Sderaadt 			/* re-exec to apply new unveil */
2703e05b07bSderaadt 			closefrom(0);
271bf6d4de2Sderaadt 			execv(_PATH_GETTY, argv);
272bf6d4de2Sderaadt 			exit(0);
273bf6d4de2Sderaadt 		}
274df930be7Sderaadt 		if (OPset || EPset || APset)
275df930be7Sderaadt 			APset++, OPset++, EPset++;
276df930be7Sderaadt 		setdefaults();
277df930be7Sderaadt 		(void)tcflush(0, TCIOFLUSH);	/* clear out the crap */
278df930be7Sderaadt 		ioctl(0, FIONBIO, &off);	/* turn off non-blocking mode */
279df930be7Sderaadt 
280df930be7Sderaadt 		if (IS)
281df930be7Sderaadt 			cfsetispeed(&tmode, IS);
282df930be7Sderaadt 		else if (SP)
283df930be7Sderaadt 			cfsetispeed(&tmode, SP);
284df930be7Sderaadt 		if (OS)
285df930be7Sderaadt 			cfsetospeed(&tmode, OS);
286df930be7Sderaadt 		else if (SP)
287df930be7Sderaadt 			cfsetospeed(&tmode, SP);
288df930be7Sderaadt 		setflags(0);
289df930be7Sderaadt 		setchars();
290df69c215Sderaadt 		if (tcsetattr(0, TCSANOW, &tmode) == -1) {
291df930be7Sderaadt 			syslog(LOG_ERR, "%s: %m", ttyn);
292df930be7Sderaadt 			exit(1);
293df930be7Sderaadt 		}
294df930be7Sderaadt 		if (AB) {
295df930be7Sderaadt 			tname = autobaud();
296df930be7Sderaadt 			continue;
297df930be7Sderaadt 		}
298df930be7Sderaadt 		if (PS) {
299df930be7Sderaadt 			tname = portselector();
300df930be7Sderaadt 			continue;
301df930be7Sderaadt 		}
302df930be7Sderaadt 		if (CL && *CL)
303df930be7Sderaadt 			putpad(CL);
30430d77a25Stedu 		strlcpy(globalhostname, HN, sizeof(globalhostname));
305df930be7Sderaadt 		if (IM && *IM)
306df930be7Sderaadt 			putf(IM);
307df930be7Sderaadt 		if (TO) {
308df930be7Sderaadt 			signal(SIGALRM, dingdong);
309df930be7Sderaadt 			alarm(TO);
310df930be7Sderaadt 		}
31154eda240Stedu 		if (getname()) {
31252113b74Sderaadt 			int i;
313df930be7Sderaadt 
314df930be7Sderaadt 			oflush();
315df930be7Sderaadt 			alarm(0);
316df930be7Sderaadt 			signal(SIGALRM, SIG_DFL);
317df930be7Sderaadt 			if (name[0] == '-') {
31839235a5fSderaadt 				xputs("user names may not start with '-'.");
319df930be7Sderaadt 				continue;
320df930be7Sderaadt 			}
321df930be7Sderaadt 			if (!(upper || lower || digit))
322df930be7Sderaadt 				continue;
323df930be7Sderaadt 			setflags(2);
324df930be7Sderaadt 			if (crmod) {
325df930be7Sderaadt 				tmode.c_iflag |= ICRNL;
326df930be7Sderaadt 				tmode.c_oflag |= ONLCR;
327df930be7Sderaadt 			}
328e095ce90Sbenno 			if (UC) {
3298f901b87Stholo 				tmode.c_iflag |= IUCLC;
3308f901b87Stholo 				tmode.c_oflag |= OLCUC;
3318f901b87Stholo 				tmode.c_lflag |= XCASE;
3328f901b87Stholo 			}
3338f901b87Stholo 			if (lower || LC) {
3348f901b87Stholo 				tmode.c_iflag &= ~IUCLC;
3358f901b87Stholo 				tmode.c_oflag &= ~OLCUC;
3368f901b87Stholo 				tmode.c_lflag &= ~XCASE;
3378f901b87Stholo 			}
338df69c215Sderaadt 			if (tcsetattr(0, TCSANOW, &tmode) == -1) {
339df930be7Sderaadt 				syslog(LOG_ERR, "%s: %m", ttyn);
340df930be7Sderaadt 				exit(1);
341df930be7Sderaadt 			}
342df930be7Sderaadt 			signal(SIGINT, SIG_DFL);
343c9899b11Skrw 			for (i = 0; environ[i] != NULL; i++)
344df930be7Sderaadt 				env[i] = environ[i];
345df930be7Sderaadt 			makeenv(&env[i]);
346df930be7Sderaadt 
347df930be7Sderaadt 			limit.rlim_max = RLIM_INFINITY;
348df930be7Sderaadt 			limit.rlim_cur = RLIM_INFINITY;
349df930be7Sderaadt 			(void)setrlimit(RLIMIT_CPU, &limit);
350c9899b11Skrw 			execle(LO, "login", "-p", "--", name, NULL, env);
351df930be7Sderaadt 			syslog(LOG_ERR, "%s: %m", LO);
352df930be7Sderaadt 			exit(1);
353df930be7Sderaadt 		}
354df930be7Sderaadt 		alarm(0);
355df930be7Sderaadt 		signal(SIGALRM, SIG_DFL);
356df930be7Sderaadt 		signal(SIGINT, SIG_IGN);
357df930be7Sderaadt 		if (NX && *NX)
358df930be7Sderaadt 			tname = NX;
359df930be7Sderaadt 	}
360df930be7Sderaadt }
361df930be7Sderaadt 
362df930be7Sderaadt static int
3635b48e80aSderaadt getname(void)
364df930be7Sderaadt {
365cf0bd593Sderaadt 	unsigned char cs;
36652113b74Sderaadt 	int c, r;
36752113b74Sderaadt 	char *np;
368df930be7Sderaadt 
369df930be7Sderaadt 	/*
370df930be7Sderaadt 	 * Interrupt may happen if we use CBREAK mode
371df930be7Sderaadt 	 */
372df930be7Sderaadt 	signal(SIGINT, interrupt);
373df930be7Sderaadt 	setflags(1);
374df930be7Sderaadt 	prompt();
375df930be7Sderaadt 	if (PF > 0) {
376df930be7Sderaadt 		oflush();
377df930be7Sderaadt 		sleep(PF);
378df930be7Sderaadt 		PF = 0;
379df930be7Sderaadt 	}
380df69c215Sderaadt 	if (tcsetattr(0, TCSANOW, &tmode) == -1) {
381df930be7Sderaadt 		syslog(LOG_ERR, "%s: %m", ttyn);
382df930be7Sderaadt 		exit(1);
383df930be7Sderaadt 	}
384df930be7Sderaadt 	crmod = digit = lower = upper = 0;
385df930be7Sderaadt 	np = name;
386df930be7Sderaadt 	for (;;) {
387df930be7Sderaadt 		oflush();
38852113b74Sderaadt 		r = read(STDIN_FILENO, &cs, 1);
38952113b74Sderaadt 		if (r <= 0) {
39052113b74Sderaadt 			if (r == -1 && errno == EINTR && interrupt_flag) {
39152113b74Sderaadt 				interrupt_flag = 0;
39252113b74Sderaadt 				return (0);
39352113b74Sderaadt 			}
394df930be7Sderaadt 			exit(0);
39552113b74Sderaadt 		}
396ba2216bdSderaadt 		/* Handle 'printables' we cannot erase */
397ba2216bdSderaadt 		if (cs == CTRL('L') || cs == CTRL('K'))
398ba2216bdSderaadt 			continue;
399ba2216bdSderaadt 		if (cs == '\t')
400ba2216bdSderaadt 			cs = ' ';
401df930be7Sderaadt 		if ((c = cs&0177) == 0)
402df930be7Sderaadt 			return (0);
403cf0bd593Sderaadt 
404df930be7Sderaadt 		if (c == EOT)
405df930be7Sderaadt 			exit(1);
4062b7dee8fSderaadt 		if (c == '\r' || c == '\n' || np >= name + sizeof name -1) {
407df930be7Sderaadt 			putf("\r\n");
408df930be7Sderaadt 			break;
409df930be7Sderaadt 		}
410df930be7Sderaadt 		if (islower(c))
411df930be7Sderaadt 			lower = 1;
412df930be7Sderaadt 		else if (isupper(c))
413df930be7Sderaadt 			upper = 1;
41447625c84Sderaadt 		else if (c == ERASE || c == '\b') {
415df930be7Sderaadt 			if (np > name) {
416ba2216bdSderaadt 				if (*--np == '\033')
417ba2216bdSderaadt 					xputs("\b\b  \b\b");
418ba2216bdSderaadt 				else if (isprint(*np))
41939235a5fSderaadt 					xputs("\b \b");
420df930be7Sderaadt 			}
421df930be7Sderaadt 			continue;
42247625c84Sderaadt 		} else if (c == KILL) {
423df930be7Sderaadt 			putchr('\r');
424ba2216bdSderaadt 			putf(LM);
425ba2216bdSderaadt 			while (np > name) {
426ba2216bdSderaadt 				if (*--np == '\033')
427ba2216bdSderaadt 					xputs("  ");
428ba2216bdSderaadt 				else if (isprint(*np))
429ba2216bdSderaadt 					putchr(' ');
430ba2216bdSderaadt 			}
431ba2216bdSderaadt 			putchr('\r');
432df930be7Sderaadt 			prompt();
433df930be7Sderaadt 			np = name;
434df930be7Sderaadt 			continue;
435df930be7Sderaadt 		} else if (isdigit(c))
436df930be7Sderaadt 			digit++;
437df930be7Sderaadt 		if (IG && (c <= ' ' || c > 0176))
438df930be7Sderaadt 			continue;
439df930be7Sderaadt 		*np++ = c;
440979c5072Sderaadt 		if (c == '\033') {
441979c5072Sderaadt 			putchr('^');
442979c5072Sderaadt 			putchr('[');
443979c5072Sderaadt 		} else
444df930be7Sderaadt 			putchr(cs);
445df930be7Sderaadt 	}
446df930be7Sderaadt 	signal(SIGINT, SIG_IGN);
44752113b74Sderaadt 	if (interrupt_flag) {
44852113b74Sderaadt 		interrupt_flag = 0;
44952113b74Sderaadt 		return (0);
45052113b74Sderaadt 	}
451df930be7Sderaadt 	*np = 0;
452df930be7Sderaadt 	if (c == '\r')
453df930be7Sderaadt 		crmod = 1;
45454eda240Stedu 	return (1);
455df930be7Sderaadt }
456df930be7Sderaadt 
457df930be7Sderaadt static void
4585b48e80aSderaadt putpad(char *s)
459df930be7Sderaadt {
460a5553e71Sderaadt 	int pad = 0;
461df930be7Sderaadt 	speed_t ospeed = cfgetospeed(&tmode);
462df930be7Sderaadt 
4634207a9b6Sderaadt 	if (isdigit((unsigned char)*s)) {
4644207a9b6Sderaadt 		while (isdigit((unsigned char)*s)) {
465df930be7Sderaadt 			pad *= 10;
466df930be7Sderaadt 			pad += *s++ - '0';
467df930be7Sderaadt 		}
468df930be7Sderaadt 		pad *= 10;
4694207a9b6Sderaadt 		if (*s == '.' && isdigit((unsigned char)s[1])) {
470df930be7Sderaadt 			pad += s[1] - '0';
471df930be7Sderaadt 			s += 2;
472df930be7Sderaadt 		}
473df930be7Sderaadt 	}
474df930be7Sderaadt 
47539235a5fSderaadt 	xputs(s);
476df930be7Sderaadt 	/*
477df930be7Sderaadt 	 * If no delay needed, or output speed is
478df930be7Sderaadt 	 * not comprehensible, then don't try to delay.
479df930be7Sderaadt 	 */
480df930be7Sderaadt 	if (pad == 0 || ospeed <= 0)
481df930be7Sderaadt 		return;
482df930be7Sderaadt 
483df930be7Sderaadt 	/*
484df930be7Sderaadt 	 * Round up by a half a character frame, and then do the delay.
485df930be7Sderaadt 	 * Too bad there are no user program accessible programmed delays.
486df930be7Sderaadt 	 * Transmitting pad characters slows many terminals down and also
487df930be7Sderaadt 	 * loads the system.
488df930be7Sderaadt 	 */
489df930be7Sderaadt 	pad = (pad * ospeed + 50000) / 100000;
490df930be7Sderaadt 	while (pad--)
491df930be7Sderaadt 		putchr(*PC);
492df930be7Sderaadt }
493df930be7Sderaadt 
494df930be7Sderaadt static void
4955b48e80aSderaadt xputs(char *s)
496df930be7Sderaadt {
497df930be7Sderaadt 	while (*s)
498df930be7Sderaadt 		putchr(*s++);
499df930be7Sderaadt }
500df930be7Sderaadt 
501df930be7Sderaadt char	outbuf[OBUFSIZ];
502df930be7Sderaadt int	obufcnt = 0;
503df930be7Sderaadt 
504df930be7Sderaadt static void
5055b48e80aSderaadt putchr(int cc)
506df930be7Sderaadt {
507df930be7Sderaadt 	char c;
508df930be7Sderaadt 
509df930be7Sderaadt 	c = cc;
510df930be7Sderaadt 	if (!NP) {
511df930be7Sderaadt 		c |= partab[c&0177] & 0200;
512df930be7Sderaadt 		if (OP)
513df930be7Sderaadt 			c ^= 0200;
514df930be7Sderaadt 	}
515df930be7Sderaadt 	if (!UB) {
516df930be7Sderaadt 		outbuf[obufcnt++] = c;
517df930be7Sderaadt 		if (obufcnt >= OBUFSIZ)
518df930be7Sderaadt 			oflush();
519df930be7Sderaadt 	} else
520df930be7Sderaadt 		write(STDOUT_FILENO, &c, 1);
521df930be7Sderaadt }
522df930be7Sderaadt 
523df930be7Sderaadt static void
5245b48e80aSderaadt oflush(void)
525df930be7Sderaadt {
526df930be7Sderaadt 	if (obufcnt)
527df930be7Sderaadt 		write(STDOUT_FILENO, outbuf, obufcnt);
528df930be7Sderaadt 	obufcnt = 0;
529df930be7Sderaadt }
530df930be7Sderaadt 
531df930be7Sderaadt static void
5325b48e80aSderaadt prompt(void)
533df930be7Sderaadt {
534df930be7Sderaadt 
535df930be7Sderaadt 	putf(LM);
536df930be7Sderaadt 	if (CO)
537df930be7Sderaadt 		putchr('\n');
538df930be7Sderaadt }
539df930be7Sderaadt 
540df930be7Sderaadt static void
5415b48e80aSderaadt putf(char *cp)
542df930be7Sderaadt {
543df930be7Sderaadt 	char *slash, db[100];
54452113b74Sderaadt 	time_t t;
545df930be7Sderaadt 
546df930be7Sderaadt 	while (*cp) {
547df930be7Sderaadt 		if (*cp != '%') {
548df930be7Sderaadt 			putchr(*cp++);
549df930be7Sderaadt 			continue;
550df930be7Sderaadt 		}
551df930be7Sderaadt 		switch (*++cp) {
552df930be7Sderaadt 
553df930be7Sderaadt 		case 't':
554df930be7Sderaadt 			slash = strrchr(ttyn, '/');
555df930be7Sderaadt 			if (slash == (char *) 0)
55639235a5fSderaadt 				xputs(ttyn);
557df930be7Sderaadt 			else
55839235a5fSderaadt 				xputs(&slash[1]);
559df930be7Sderaadt 			break;
560df930be7Sderaadt 
561df930be7Sderaadt 		case 'h':
56230d77a25Stedu 			xputs(globalhostname);
563df930be7Sderaadt 			break;
564df930be7Sderaadt 
565df930be7Sderaadt 		case 'd': {
56673fe6daaSflorian 			struct tm *tm;
56773fe6daaSflorian 			time(&t);
56873fe6daaSflorian 			if ((tm = localtime(&t)) != NULL)
56973fe6daaSflorian 				if (strftime(db, sizeof(db),
57073fe6daaSflorian 				    "%l:%M%p on %A, %d %B %Y", tm) != 0)
57139235a5fSderaadt 					xputs(db);
572df930be7Sderaadt 			break;
57352113b74Sderaadt 		}
574df930be7Sderaadt 
575df930be7Sderaadt 		case 's':
57639235a5fSderaadt 			xputs(kerninfo.sysname);
577df930be7Sderaadt 			break;
578df930be7Sderaadt 
579df930be7Sderaadt 		case 'm':
58039235a5fSderaadt 			xputs(kerninfo.machine);
581df930be7Sderaadt 			break;
582df930be7Sderaadt 
583df930be7Sderaadt 		case 'r':
58439235a5fSderaadt 			xputs(kerninfo.release);
585df930be7Sderaadt 			break;
586df930be7Sderaadt 
587df930be7Sderaadt 		case 'v':
58839235a5fSderaadt 			xputs(kerninfo.version);
589df930be7Sderaadt 			break;
590df930be7Sderaadt 
591df930be7Sderaadt 		case '%':
592df930be7Sderaadt 			putchr('%');
593df930be7Sderaadt 			break;
594df930be7Sderaadt 		}
595df930be7Sderaadt 		cp++;
596df930be7Sderaadt 	}
597df930be7Sderaadt }
598