xref: /freebsd/libexec/getty/main.c (revision 6574b8ed19b093f0af09501d2c9676c28993cb97)
1 /*-
2  * Copyright (c) 1980, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #ifndef lint
31 static const char copyright[] =
32 "@(#) Copyright (c) 1980, 1993\n\
33 	The Regents of the University of California.  All rights reserved.\n";
34 #endif /* not lint */
35 
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)from: main.c	8.1 (Berkeley) 6/20/93";
39 #endif
40 #endif /* not lint */
41 #include <sys/cdefs.h>
42 __FBSDID("$FreeBSD$");
43 
44 #include <sys/param.h>
45 #include <sys/ioctl.h>
46 #include <sys/time.h>
47 #include <sys/resource.h>
48 #include <sys/stat.h>
49 #include <sys/ttydefaults.h>
50 #include <sys/utsname.h>
51 
52 #include <ctype.h>
53 #include <errno.h>
54 #include <fcntl.h>
55 #include <locale.h>
56 #include <libutil.h>
57 #include <setjmp.h>
58 #include <signal.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <syslog.h>
62 #include <termios.h>
63 #include <time.h>
64 #include <unistd.h>
65 
66 #include "gettytab.h"
67 #include "extern.h"
68 #include "pathnames.h"
69 
70 /*
71  * Set the amount of running time that getty should accumulate
72  * before deciding that something is wrong and exit.
73  */
74 #define GETTY_TIMEOUT	60 /* seconds */
75 
76 #undef CTRL
77 #define CTRL(x)  (x&037)
78 
79 /* defines for auto detection of incoming PPP calls (->PAP/CHAP) */
80 
81 #define PPP_FRAME           0x7e  /* PPP Framing character */
82 #define PPP_STATION         0xff  /* "All Station" character */
83 #define PPP_ESCAPE          0x7d  /* Escape Character */
84 #define PPP_CONTROL         0x03  /* PPP Control Field */
85 #define PPP_CONTROL_ESCAPED 0x23  /* PPP Control Field, escaped */
86 #define PPP_LCP_HI          0xc0  /* LCP protocol - high byte */
87 #define PPP_LCP_LOW         0x21  /* LCP protocol - low byte */
88 
89 /* original mode; flags've been reset using values from <sys/ttydefaults.h> */
90 struct termios omode;
91 /* current mode */
92 struct termios tmode;
93 
94 int crmod, digit, lower, upper;
95 
96 char	hostname[MAXHOSTNAMELEN];
97 char	name[MAXLOGNAME*3];
98 char	dev[] = _PATH_DEV;
99 char	ttyn[32];
100 
101 #define	OBUFSIZ		128
102 #define	TABBUFSIZ	512
103 
104 char	defent[TABBUFSIZ];
105 char	tabent[TABBUFSIZ];
106 const	char *tname;
107 
108 char	*env[128];
109 
110 char partab[] = {
111 	0001,0201,0201,0001,0201,0001,0001,0201,
112 	0202,0004,0003,0205,0005,0206,0201,0001,
113 	0201,0001,0001,0201,0001,0201,0201,0001,
114 	0001,0201,0201,0001,0201,0001,0001,0201,
115 	0200,0000,0000,0200,0000,0200,0200,0000,
116 	0000,0200,0200,0000,0200,0000,0000,0200,
117 	0000,0200,0200,0000,0200,0000,0000,0200,
118 	0200,0000,0000,0200,0000,0200,0200,0000,
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 	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,0201
127 };
128 
129 #define	ERASE	tmode.c_cc[VERASE]
130 #define	KILL	tmode.c_cc[VKILL]
131 #define	EOT	tmode.c_cc[VEOF]
132 
133 #define	puts	Gputs
134 
135 static void	defttymode(void);
136 static void	dingdong(int);
137 static void	dogettytab(void);
138 static int	getname(void);
139 static void	interrupt(int);
140 static void	oflush(void);
141 static void	prompt(void);
142 static void	putchr(int);
143 static void	putf(const char *);
144 static void	putpad(const char *);
145 static void	puts(const char *);
146 static void	timeoverrun(int);
147 static char	*getline(int);
148 static void	setttymode(int);
149 static int	opentty(const char *, int);
150 
151 jmp_buf timeout;
152 
153 static void
154 dingdong(int signo __unused)
155 {
156 	alarm(0);
157 	longjmp(timeout, 1);
158 }
159 
160 jmp_buf	intrupt;
161 
162 static void
163 interrupt(int signo __unused)
164 {
165 	longjmp(intrupt, 1);
166 }
167 
168 /*
169  * Action to take when getty is running too long.
170  */
171 static void
172 timeoverrun(int signo __unused)
173 {
174 
175 	syslog(LOG_ERR, "getty exiting due to excessive running time");
176 	exit(1);
177 }
178 
179 int
180 main(int argc, char *argv[])
181 {
182 	extern	char **environ;
183 	int first_sleep = 1, first_time = 1;
184 	struct rlimit limit;
185 	int rval;
186 
187 	signal(SIGINT, SIG_IGN);
188 	signal(SIGQUIT, SIG_IGN);
189 
190 	openlog("getty", LOG_CONS|LOG_PID, LOG_AUTH);
191 	gethostname(hostname, sizeof(hostname) - 1);
192 	hostname[sizeof(hostname) - 1] = '\0';
193 	if (hostname[0] == '\0')
194 		strcpy(hostname, "Amnesiac");
195 
196 	/*
197 	 * Limit running time to deal with broken or dead lines.
198 	 */
199 	(void)signal(SIGXCPU, timeoverrun);
200 	limit.rlim_max = RLIM_INFINITY;
201 	limit.rlim_cur = GETTY_TIMEOUT;
202 	(void)setrlimit(RLIMIT_CPU, &limit);
203 
204 	gettable("default", defent);
205 	gendefaults();
206 	tname = "default";
207 	if (argc > 1)
208 		tname = argv[1];
209 
210 	/*
211 	 * The following is a work around for vhangup interactions
212 	 * which cause great problems getting window systems started.
213 	 * If the tty line is "-", we do the old style getty presuming
214 	 * that the file descriptors are already set up for us.
215 	 * J. Gettys - MIT Project Athena.
216 	 */
217 	if (argc <= 2 || strcmp(argv[2], "-") == 0)
218 	    strcpy(ttyn, ttyname(STDIN_FILENO));
219 	else {
220 	    strcpy(ttyn, dev);
221 	    strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
222 	    if (strcmp(argv[0], "+") != 0) {
223 		chown(ttyn, 0, 0);
224 		chmod(ttyn, 0600);
225 		revoke(ttyn);
226 
227 		/*
228 		 * Do the first scan through gettytab.
229 		 * Terminal mode parameters will be wrong until
230 		 * defttymode() called, but they're irrelevant for
231 		 * the initial setup of the terminal device.
232 		 */
233 		dogettytab();
234 
235 		/*
236 		 * Init or answer modem sequence has been specified.
237 		 */
238 		if (IC || AC) {
239 			if (!opentty(ttyn, O_RDWR|O_NONBLOCK))
240 				exit(1);
241 			defttymode();
242 			setttymode(1);
243 		}
244 
245 		if (IC) {
246 			if (getty_chat(IC, CT, DC) > 0) {
247 				syslog(LOG_ERR, "modem init problem on %s", ttyn);
248 				(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
249 				exit(1);
250 			}
251 		}
252 
253 		if (AC) {
254 			int i, rfds;
255 			struct timeval to;
256 
257         		rfds = 1 << 0;	/* FD_SET */
258         		to.tv_sec = RT;
259         		to.tv_usec = 0;
260         		i = select(32, (fd_set*)&rfds, (fd_set*)NULL,
261         			       (fd_set*)NULL, RT ? &to : NULL);
262         		if (i < 0) {
263 				syslog(LOG_ERR, "select %s: %m", ttyn);
264 			} else if (i == 0) {
265 				syslog(LOG_NOTICE, "recycle tty %s", ttyn);
266 				(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
267 				exit(0);  /* recycle for init */
268 			}
269 			i = getty_chat(AC, CT, DC);
270 			if (i > 0) {
271 				syslog(LOG_ERR, "modem answer problem on %s", ttyn);
272 				(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
273 				exit(1);
274 			}
275 		} else { /* maybe blocking open */
276 			if (!opentty(ttyn, O_RDWR | (NC ? O_NONBLOCK : 0 )))
277 				exit(1);
278 		}
279 	    }
280 	}
281 
282 	defttymode();
283 	for (;;) {
284 
285 		/*
286 		 * if a delay was specified then sleep for that
287 		 * number of seconds before writing the initial prompt
288 		 */
289 		if (first_sleep && DE) {
290 		    sleep(DE);
291 		    /* remove any noise */
292 		    (void)tcflush(STDIN_FILENO, TCIOFLUSH);
293 		}
294 		first_sleep = 0;
295 
296 		setttymode(0);
297 		if (AB) {
298 			tname = autobaud();
299 			dogettytab();
300 			continue;
301 		}
302 		if (PS) {
303 			tname = portselector();
304 			dogettytab();
305 			continue;
306 		}
307 		if (CL && *CL)
308 			putpad(CL);
309 		edithost(HE);
310 
311 		/* if this is the first time through this, and an
312 		   issue file has been given, then send it */
313 		if (first_time && IF) {
314 			int fd;
315 
316 			if ((fd = open(IF, O_RDONLY)) != -1) {
317 				char * cp;
318 
319 				while ((cp = getline(fd)) != NULL) {
320 					  putf(cp);
321 				}
322 				close(fd);
323 			}
324 		}
325 		first_time = 0;
326 
327 		if (IM && *IM && !(PL && PP))
328 			putf(IM);
329 		if (setjmp(timeout)) {
330 			cfsetispeed(&tmode, B0);
331 			cfsetospeed(&tmode, B0);
332 			(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
333 			exit(1);
334 		}
335 		if (TO) {
336 			signal(SIGALRM, dingdong);
337 			alarm(TO);
338 		}
339 
340 		rval = 0;
341 		if (AL) {
342 			const char *p = AL;
343 			char *q = name;
344 
345 			while (*p && q < &name[sizeof name - 1]) {
346 				if (isupper(*p))
347 					upper = 1;
348 				else if (islower(*p))
349 					lower = 1;
350 				else if (isdigit(*p))
351 					digit = 1;
352 				*q++ = *p++;
353 			}
354 		} else if (!(PL && PP))
355 			rval = getname();
356 		if (rval == 2 || (PL && PP)) {
357 			oflush();
358 			alarm(0);
359 			limit.rlim_max = RLIM_INFINITY;
360 			limit.rlim_cur = RLIM_INFINITY;
361 			(void)setrlimit(RLIMIT_CPU, &limit);
362 			execle(PP, "ppplogin", ttyn, (char *) 0, env);
363 			syslog(LOG_ERR, "%s: %m", PP);
364 			exit(1);
365 		} else if (rval || AL) {
366 			int i;
367 
368 			oflush();
369 			alarm(0);
370 			signal(SIGALRM, SIG_DFL);
371 			if (name[0] == '\0')
372 				continue;
373 			if (name[0] == '-') {
374 				puts("user names may not start with '-'.");
375 				continue;
376 			}
377 			if (!(upper || lower || digit)) {
378 				if (AL) {
379 					syslog(LOG_ERR,
380 					    "invalid auto-login name: %s", AL);
381 					exit(1);
382 				} else
383 					continue;
384 			}
385 			set_flags(2);
386 			if (crmod) {
387 				tmode.c_iflag |= ICRNL;
388 				tmode.c_oflag |= ONLCR;
389 			}
390 #if REALLY_OLD_TTYS
391 			if (upper || UC)
392 				tmode.sg_flags |= LCASE;
393 			if (lower || LC)
394 				tmode.sg_flags &= ~LCASE;
395 #endif
396 			if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
397 				syslog(LOG_ERR, "tcsetattr %s: %m", ttyn);
398 				exit(1);
399 			}
400 			signal(SIGINT, SIG_DFL);
401 			for (i = 0; environ[i] != (char *)0; i++)
402 				env[i] = environ[i];
403 			makeenv(&env[i]);
404 
405 			limit.rlim_max = RLIM_INFINITY;
406 			limit.rlim_cur = RLIM_INFINITY;
407 			(void)setrlimit(RLIMIT_CPU, &limit);
408 			execle(LO, "login", AL ? "-fp" : "-p", name,
409 			    (char *) 0, env);
410 			syslog(LOG_ERR, "%s: %m", LO);
411 			exit(1);
412 		}
413 		alarm(0);
414 		signal(SIGALRM, SIG_DFL);
415 		signal(SIGINT, SIG_IGN);
416 		if (NX && *NX) {
417 			tname = NX;
418 			dogettytab();
419 		}
420 	}
421 }
422 
423 static int
424 opentty(const char *tty, int flags)
425 {
426 	int i;
427 	int failopenlogged = 0;
428 
429 	while ((i = open(tty, flags)) == -1)
430 	{
431 		if (!failopenlogged) {
432 			syslog(LOG_ERR, "open %s: %m", tty);
433 			failopenlogged = 1;
434 		}
435 		sleep(60);
436 	}
437 	if (login_tty(i) < 0) {
438 		if (daemon(0,0) < 0) {
439 			syslog(LOG_ERR,"daemon: %m");
440 			close(i);
441 			return 0;
442 		}
443 		if (login_tty(i) < 0) {
444 			syslog(LOG_ERR, "login_tty %s: %m", tty);
445 			close(i);
446 			return 0;
447 		}
448 	}
449 	return 1;
450 }
451 
452 static void
453 defttymode(void)
454 {
455 	struct termios def;
456 
457 	/* Start with default tty settings. */
458 	if (tcgetattr(STDIN_FILENO, &tmode) < 0) {
459 		syslog(LOG_ERR, "tcgetattr %s: %m", ttyn);
460 		exit(1);
461 	}
462 	omode = tmode; /* fill c_cc for dogettytab() */
463 	dogettytab();
464 	/*
465 	 * Don't rely on the driver too much, and initialize crucial
466 	 * things according to <sys/ttydefaults.h>.  Avoid clobbering
467 	 * the c_cc[] settings however, the console drivers might wish
468 	 * to leave their idea of the preferred VERASE key value
469 	 * there.
470 	 */
471 	cfmakesane(&def);
472 	tmode.c_iflag = def.c_iflag;
473 	tmode.c_oflag = def.c_oflag;
474 	tmode.c_lflag = def.c_lflag;
475 	tmode.c_cflag = def.c_cflag;
476 	if (NC)
477 		tmode.c_cflag |= CLOCAL;
478 	omode = tmode;
479 }
480 
481 static void
482 setttymode(int raw)
483 {
484 	int off = 0;
485 
486 	(void)tcflush(STDIN_FILENO, TCIOFLUSH);	/* clear out the crap */
487 	ioctl(STDIN_FILENO, FIONBIO, &off);	/* turn off non-blocking mode */
488 	ioctl(STDIN_FILENO, FIOASYNC, &off);	/* ditto for async mode */
489 
490 	if (IS)
491 		cfsetispeed(&tmode, speed(IS));
492 	else if (SP)
493 		cfsetispeed(&tmode, speed(SP));
494 	if (OS)
495 		cfsetospeed(&tmode, speed(OS));
496 	else if (SP)
497 		cfsetospeed(&tmode, speed(SP));
498 	set_flags(0);
499 	setchars();
500 	if (raw)
501 		cfmakeraw(&tmode);
502 	if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
503 		syslog(LOG_ERR, "tcsetattr %s: %m", ttyn);
504 		exit(1);
505 	}
506 }
507 
508 
509 static int
510 getname(void)
511 {
512 	int c;
513 	char *np;
514 	unsigned char cs;
515 	int ppp_state = 0;
516 	int ppp_connection = 0;
517 
518 	/*
519 	 * Interrupt may happen if we use CBREAK mode
520 	 */
521 	if (setjmp(intrupt)) {
522 		signal(SIGINT, SIG_IGN);
523 		return (0);
524 	}
525 	signal(SIGINT, interrupt);
526 	set_flags(1);
527 	prompt();
528 	oflush();
529 	if (PF > 0) {
530 		sleep(PF);
531 		PF = 0;
532 	}
533 	if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
534 		syslog(LOG_ERR, "%s: %m", ttyn);
535 		exit(1);
536 	}
537 	crmod = digit = lower = upper = 0;
538 	np = name;
539 	for (;;) {
540 		oflush();
541 		if (read(STDIN_FILENO, &cs, 1) <= 0)
542 			exit(0);
543 		if ((c = cs&0177) == 0)
544 			return (0);
545 
546 		/* PPP detection state machine..
547 		   Look for sequences:
548 		   PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or
549 		   PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC)
550 		   See RFC1662.
551 		   Derived from code from Michael Hancock, <michaelh@cet.co.jp>
552 		   and Erik 'PPP' Olson, <eriko@wrq.com>
553 		 */
554 
555 		if (PP && (cs == PPP_FRAME)) {
556 			ppp_state = 1;
557 		} else if (ppp_state == 1 && cs == PPP_STATION) {
558 			ppp_state = 2;
559 		} else if (ppp_state == 2 && cs == PPP_ESCAPE) {
560 			ppp_state = 3;
561 		} else if ((ppp_state == 2 && cs == PPP_CONTROL)
562 			|| (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) {
563 			ppp_state = 4;
564 		} else if (ppp_state == 4 && cs == PPP_LCP_HI) {
565 			ppp_state = 5;
566 		} else if (ppp_state == 5 && cs == PPP_LCP_LOW) {
567 			ppp_connection = 1;
568 			break;
569 		} else {
570 			ppp_state = 0;
571 		}
572 
573 		if (c == EOT || c == CTRL('d'))
574 			exit(0);
575 		if (c == '\r' || c == '\n' || np >= &name[sizeof name-1]) {
576 			putf("\r\n");
577 			break;
578 		}
579 		if (islower(c))
580 			lower = 1;
581 		else if (isupper(c))
582 			upper = 1;
583 		else if (c == ERASE || c == '\b' || c == 0177) {
584 			if (np > name) {
585 				np--;
586 				if (cfgetospeed(&tmode) >= 1200)
587 					puts("\b \b");
588 				else
589 					putchr(cs);
590 			}
591 			continue;
592 		} else if (c == KILL || c == CTRL('u')) {
593 			putchr('\r');
594 			if (cfgetospeed(&tmode) < 1200)
595 				putchr('\n');
596 			/* this is the way they do it down under ... */
597 			else if (np > name)
598 				puts("                                     \r");
599 			prompt();
600 			digit = lower = upper = 0;
601 			np = name;
602 			continue;
603 		} else if (isdigit(c))
604 			digit = 1;
605 		if (IG && (c <= ' ' || c > 0176))
606 			continue;
607 		*np++ = c;
608 		putchr(cs);
609 	}
610 	signal(SIGINT, SIG_IGN);
611 	*np = 0;
612 	if (c == '\r')
613 		crmod = 1;
614 	if ((upper && !lower && !LC) || UC)
615 		for (np = name; *np; np++)
616 			if (isupper(*np))
617 				*np = tolower(*np);
618 	return (1 + ppp_connection);
619 }
620 
621 static void
622 putpad(const char *s)
623 {
624 	int pad = 0;
625 	speed_t ospeed = cfgetospeed(&tmode);
626 
627 	if (isdigit(*s)) {
628 		while (isdigit(*s)) {
629 			pad *= 10;
630 			pad += *s++ - '0';
631 		}
632 		pad *= 10;
633 		if (*s == '.' && isdigit(s[1])) {
634 			pad += s[1] - '0';
635 			s += 2;
636 		}
637 	}
638 
639 	puts(s);
640 	/*
641 	 * If no delay needed, or output speed is
642 	 * not comprehensible, then don't try to delay.
643 	 */
644 	if (pad == 0 || ospeed <= 0)
645 		return;
646 
647 	/*
648 	 * Round up by a half a character frame, and then do the delay.
649 	 * Too bad there are no user program accessible programmed delays.
650 	 * Transmitting pad characters slows many terminals down and also
651 	 * loads the system.
652 	 */
653 	pad = (pad * ospeed + 50000) / 100000;
654 	while (pad--)
655 		putchr(*PC);
656 }
657 
658 static void
659 puts(const char *s)
660 {
661 	while (*s)
662 		putchr(*s++);
663 }
664 
665 char	outbuf[OBUFSIZ];
666 int	obufcnt = 0;
667 
668 static void
669 putchr(int cc)
670 {
671 	char c;
672 
673 	c = cc;
674 	if (!NP) {
675 		c |= partab[c&0177] & 0200;
676 		if (OP)
677 			c ^= 0200;
678 	}
679 	if (!UB) {
680 		outbuf[obufcnt++] = c;
681 		if (obufcnt >= OBUFSIZ)
682 			oflush();
683 	} else
684 		write(STDOUT_FILENO, &c, 1);
685 }
686 
687 static void
688 oflush(void)
689 {
690 	if (obufcnt)
691 		write(STDOUT_FILENO, outbuf, obufcnt);
692 	obufcnt = 0;
693 }
694 
695 static void
696 prompt(void)
697 {
698 
699 	putf(LM);
700 	if (CO)
701 		putchr('\n');
702 }
703 
704 
705 static char *
706 getline(int fd)
707 {
708 	int i = 0;
709 	static char linebuf[512];
710 
711 	/*
712 	 * This is certainly slow, but it avoids having to include
713 	 * stdio.h unnecessarily. Issue files should be small anyway.
714 	 */
715 	while (i < (sizeof linebuf - 3) && read(fd, linebuf+i, 1)==1) {
716 		if (linebuf[i] == '\n') {
717 			/* Don't rely on newline mode, assume raw */
718 			linebuf[i++] = '\r';
719 			linebuf[i++] = '\n';
720 			linebuf[i] = '\0';
721 			return linebuf;
722 		}
723 		++i;
724 	}
725 	linebuf[i] = '\0';
726 	return i ? linebuf : 0;
727 }
728 
729 static void
730 putf(const char *cp)
731 {
732 	extern char editedhost[];
733 	time_t t;
734 	char *slash, db[100];
735 
736 	static struct utsname kerninfo;
737 
738 	if (!*kerninfo.sysname)
739 		uname(&kerninfo);
740 
741 	while (*cp) {
742 		if (*cp != '%') {
743 			putchr(*cp++);
744 			continue;
745 		}
746 		switch (*++cp) {
747 
748 		case 't':
749 			slash = strrchr(ttyn, '/');
750 			if (slash == (char *) 0)
751 				puts(ttyn);
752 			else
753 				puts(&slash[1]);
754 			break;
755 
756 		case 'h':
757 			puts(editedhost);
758 			break;
759 
760 		case 'd': {
761 			t = (time_t)0;
762 			(void)time(&t);
763 			if (Lo)
764 				(void)setlocale(LC_TIME, Lo);
765 			(void)strftime(db, sizeof(db), DF, localtime(&t));
766 			puts(db);
767 			break;
768 
769 		case 's':
770 			puts(kerninfo.sysname);
771 			break;
772 
773 		case 'm':
774 			puts(kerninfo.machine);
775 			break;
776 
777 		case 'r':
778 			puts(kerninfo.release);
779 			break;
780 
781 		case 'v':
782 			puts(kerninfo.version);
783 			break;
784 		}
785 
786 		case '%':
787 			putchr('%');
788 			break;
789 		}
790 		cp++;
791 	}
792 }
793 
794 /*
795  * Read a gettytab database entry and perform necessary quirks.
796  */
797 static void
798 dogettytab(void)
799 {
800 
801 	/* Read the database entry. */
802 	gettable(tname, tabent);
803 
804 	/*
805 	 * Avoid inheriting the parity values from the default entry
806 	 * if any of them is set in the current entry.
807 	 * Mixing different parity settings is unreasonable.
808 	 */
809 	if (OPset || EPset || APset || NPset)
810 		OPset = EPset = APset = NPset = 1;
811 
812 	/* Fill in default values for unset capabilities. */
813 	setdefaults();
814 }
815