xref: /freebsd/libexec/getty/main.c (revision da3086df1863e9aed45eb14e265c306f8bb27d80)
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 (IMP && *IMP && !(PL && PP))
328 			system(IMP);
329 		if (IM && *IM && !(PL && PP))
330 			putf(IM);
331 		if (setjmp(timeout)) {
332 			cfsetispeed(&tmode, B0);
333 			cfsetospeed(&tmode, B0);
334 			(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
335 			exit(1);
336 		}
337 		if (TO) {
338 			signal(SIGALRM, dingdong);
339 			alarm(TO);
340 		}
341 
342 		rval = 0;
343 		if (AL) {
344 			const char *p = AL;
345 			char *q = name;
346 
347 			while (*p && q < &name[sizeof name - 1]) {
348 				if (isupper(*p))
349 					upper = 1;
350 				else if (islower(*p))
351 					lower = 1;
352 				else if (isdigit(*p))
353 					digit = 1;
354 				*q++ = *p++;
355 			}
356 		} else if (!(PL && PP))
357 			rval = getname();
358 		if (rval == 2 || (PL && PP)) {
359 			oflush();
360 			alarm(0);
361 			limit.rlim_max = RLIM_INFINITY;
362 			limit.rlim_cur = RLIM_INFINITY;
363 			(void)setrlimit(RLIMIT_CPU, &limit);
364 			execle(PP, "ppplogin", ttyn, (char *) 0, env);
365 			syslog(LOG_ERR, "%s: %m", PP);
366 			exit(1);
367 		} else if (rval || AL) {
368 			int i;
369 
370 			oflush();
371 			alarm(0);
372 			signal(SIGALRM, SIG_DFL);
373 			if (name[0] == '\0')
374 				continue;
375 			if (name[0] == '-') {
376 				puts("user names may not start with '-'.");
377 				continue;
378 			}
379 			if (!(upper || lower || digit)) {
380 				if (AL) {
381 					syslog(LOG_ERR,
382 					    "invalid auto-login name: %s", AL);
383 					exit(1);
384 				} else
385 					continue;
386 			}
387 			set_flags(2);
388 			if (crmod) {
389 				tmode.c_iflag |= ICRNL;
390 				tmode.c_oflag |= ONLCR;
391 			}
392 #if REALLY_OLD_TTYS
393 			if (upper || UC)
394 				tmode.sg_flags |= LCASE;
395 			if (lower || LC)
396 				tmode.sg_flags &= ~LCASE;
397 #endif
398 			if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
399 				syslog(LOG_ERR, "tcsetattr %s: %m", ttyn);
400 				exit(1);
401 			}
402 			signal(SIGINT, SIG_DFL);
403 			for (i = 0; environ[i] != (char *)0; i++)
404 				env[i] = environ[i];
405 			makeenv(&env[i]);
406 
407 			limit.rlim_max = RLIM_INFINITY;
408 			limit.rlim_cur = RLIM_INFINITY;
409 			(void)setrlimit(RLIMIT_CPU, &limit);
410 			execle(LO, "login", AL ? "-fp" : "-p", name,
411 			    (char *) 0, env);
412 			syslog(LOG_ERR, "%s: %m", LO);
413 			exit(1);
414 		}
415 		alarm(0);
416 		signal(SIGALRM, SIG_DFL);
417 		signal(SIGINT, SIG_IGN);
418 		if (NX && *NX) {
419 			tname = NX;
420 			dogettytab();
421 		}
422 	}
423 }
424 
425 static int
426 opentty(const char *tty, int flags)
427 {
428 	int i;
429 	int failopenlogged = 0;
430 
431 	while ((i = open(tty, flags)) == -1)
432 	{
433 		if (!failopenlogged) {
434 			syslog(LOG_ERR, "open %s: %m", tty);
435 			failopenlogged = 1;
436 		}
437 		sleep(60);
438 	}
439 	if (login_tty(i) < 0) {
440 		if (daemon(0,0) < 0) {
441 			syslog(LOG_ERR,"daemon: %m");
442 			close(i);
443 			return 0;
444 		}
445 		if (login_tty(i) < 0) {
446 			syslog(LOG_ERR, "login_tty %s: %m", tty);
447 			close(i);
448 			return 0;
449 		}
450 	}
451 	return 1;
452 }
453 
454 static void
455 defttymode(void)
456 {
457 	struct termios def;
458 
459 	/* Start with default tty settings. */
460 	if (tcgetattr(STDIN_FILENO, &tmode) < 0) {
461 		syslog(LOG_ERR, "tcgetattr %s: %m", ttyn);
462 		exit(1);
463 	}
464 	omode = tmode; /* fill c_cc for dogettytab() */
465 	dogettytab();
466 	/*
467 	 * Don't rely on the driver too much, and initialize crucial
468 	 * things according to <sys/ttydefaults.h>.  Avoid clobbering
469 	 * the c_cc[] settings however, the console drivers might wish
470 	 * to leave their idea of the preferred VERASE key value
471 	 * there.
472 	 */
473 	cfmakesane(&def);
474 	tmode.c_iflag = def.c_iflag;
475 	tmode.c_oflag = def.c_oflag;
476 	tmode.c_lflag = def.c_lflag;
477 	tmode.c_cflag = def.c_cflag;
478 	if (NC)
479 		tmode.c_cflag |= CLOCAL;
480 	omode = tmode;
481 }
482 
483 static void
484 setttymode(int raw)
485 {
486 	int off = 0;
487 
488 	(void)tcflush(STDIN_FILENO, TCIOFLUSH);	/* clear out the crap */
489 	ioctl(STDIN_FILENO, FIONBIO, &off);	/* turn off non-blocking mode */
490 	ioctl(STDIN_FILENO, FIOASYNC, &off);	/* ditto for async mode */
491 
492 	if (IS)
493 		cfsetispeed(&tmode, speed(IS));
494 	else if (SP)
495 		cfsetispeed(&tmode, speed(SP));
496 	if (OS)
497 		cfsetospeed(&tmode, speed(OS));
498 	else if (SP)
499 		cfsetospeed(&tmode, speed(SP));
500 	set_flags(0);
501 	setchars();
502 	if (raw)
503 		cfmakeraw(&tmode);
504 	if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
505 		syslog(LOG_ERR, "tcsetattr %s: %m", ttyn);
506 		exit(1);
507 	}
508 }
509 
510 
511 static int
512 getname(void)
513 {
514 	int c;
515 	char *np;
516 	unsigned char cs;
517 	int ppp_state = 0;
518 	int ppp_connection = 0;
519 
520 	/*
521 	 * Interrupt may happen if we use CBREAK mode
522 	 */
523 	if (setjmp(intrupt)) {
524 		signal(SIGINT, SIG_IGN);
525 		return (0);
526 	}
527 	signal(SIGINT, interrupt);
528 	set_flags(1);
529 	prompt();
530 	oflush();
531 	if (PF > 0) {
532 		sleep(PF);
533 		PF = 0;
534 	}
535 	if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
536 		syslog(LOG_ERR, "%s: %m", ttyn);
537 		exit(1);
538 	}
539 	crmod = digit = lower = upper = 0;
540 	np = name;
541 	for (;;) {
542 		oflush();
543 		if (read(STDIN_FILENO, &cs, 1) <= 0)
544 			exit(0);
545 		if ((c = cs&0177) == 0)
546 			return (0);
547 
548 		/* PPP detection state machine..
549 		   Look for sequences:
550 		   PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or
551 		   PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC)
552 		   See RFC1662.
553 		   Derived from code from Michael Hancock, <michaelh@cet.co.jp>
554 		   and Erik 'PPP' Olson, <eriko@wrq.com>
555 		 */
556 
557 		if (PP && (cs == PPP_FRAME)) {
558 			ppp_state = 1;
559 		} else if (ppp_state == 1 && cs == PPP_STATION) {
560 			ppp_state = 2;
561 		} else if (ppp_state == 2 && cs == PPP_ESCAPE) {
562 			ppp_state = 3;
563 		} else if ((ppp_state == 2 && cs == PPP_CONTROL)
564 			|| (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) {
565 			ppp_state = 4;
566 		} else if (ppp_state == 4 && cs == PPP_LCP_HI) {
567 			ppp_state = 5;
568 		} else if (ppp_state == 5 && cs == PPP_LCP_LOW) {
569 			ppp_connection = 1;
570 			break;
571 		} else {
572 			ppp_state = 0;
573 		}
574 
575 		if (c == EOT || c == CTRL('d'))
576 			exit(0);
577 		if (c == '\r' || c == '\n' || np >= &name[sizeof name-1]) {
578 			putf("\r\n");
579 			break;
580 		}
581 		if (islower(c))
582 			lower = 1;
583 		else if (isupper(c))
584 			upper = 1;
585 		else if (c == ERASE || c == '\b' || c == 0177) {
586 			if (np > name) {
587 				np--;
588 				if (cfgetospeed(&tmode) >= 1200)
589 					puts("\b \b");
590 				else
591 					putchr(cs);
592 			}
593 			continue;
594 		} else if (c == KILL || c == CTRL('u')) {
595 			putchr('\r');
596 			if (cfgetospeed(&tmode) < 1200)
597 				putchr('\n');
598 			/* this is the way they do it down under ... */
599 			else if (np > name)
600 				puts("                                     \r");
601 			prompt();
602 			digit = lower = upper = 0;
603 			np = name;
604 			continue;
605 		} else if (isdigit(c))
606 			digit = 1;
607 		if (IG && (c <= ' ' || c > 0176))
608 			continue;
609 		*np++ = c;
610 		putchr(cs);
611 	}
612 	signal(SIGINT, SIG_IGN);
613 	*np = 0;
614 	if (c == '\r')
615 		crmod = 1;
616 	if ((upper && !lower && !LC) || UC)
617 		for (np = name; *np; np++)
618 			if (isupper(*np))
619 				*np = tolower(*np);
620 	return (1 + ppp_connection);
621 }
622 
623 static void
624 putpad(const char *s)
625 {
626 	int pad = 0;
627 	speed_t ospeed = cfgetospeed(&tmode);
628 
629 	if (isdigit(*s)) {
630 		while (isdigit(*s)) {
631 			pad *= 10;
632 			pad += *s++ - '0';
633 		}
634 		pad *= 10;
635 		if (*s == '.' && isdigit(s[1])) {
636 			pad += s[1] - '0';
637 			s += 2;
638 		}
639 	}
640 
641 	puts(s);
642 	/*
643 	 * If no delay needed, or output speed is
644 	 * not comprehensible, then don't try to delay.
645 	 */
646 	if (pad == 0 || ospeed <= 0)
647 		return;
648 
649 	/*
650 	 * Round up by a half a character frame, and then do the delay.
651 	 * Too bad there are no user program accessible programmed delays.
652 	 * Transmitting pad characters slows many terminals down and also
653 	 * loads the system.
654 	 */
655 	pad = (pad * ospeed + 50000) / 100000;
656 	while (pad--)
657 		putchr(*PC);
658 }
659 
660 static void
661 puts(const char *s)
662 {
663 	while (*s)
664 		putchr(*s++);
665 }
666 
667 char	outbuf[OBUFSIZ];
668 int	obufcnt = 0;
669 
670 static void
671 putchr(int cc)
672 {
673 	char c;
674 
675 	c = cc;
676 	if (!NP) {
677 		c |= partab[c&0177] & 0200;
678 		if (OP)
679 			c ^= 0200;
680 	}
681 	if (!UB) {
682 		outbuf[obufcnt++] = c;
683 		if (obufcnt >= OBUFSIZ)
684 			oflush();
685 	} else
686 		write(STDOUT_FILENO, &c, 1);
687 }
688 
689 static void
690 oflush(void)
691 {
692 	if (obufcnt)
693 		write(STDOUT_FILENO, outbuf, obufcnt);
694 	obufcnt = 0;
695 }
696 
697 static void
698 prompt(void)
699 {
700 
701 	putf(LM);
702 	if (CO)
703 		putchr('\n');
704 }
705 
706 
707 static char *
708 getline(int fd)
709 {
710 	int i = 0;
711 	static char linebuf[512];
712 
713 	/*
714 	 * This is certainly slow, but it avoids having to include
715 	 * stdio.h unnecessarily. Issue files should be small anyway.
716 	 */
717 	while (i < (sizeof linebuf - 3) && read(fd, linebuf+i, 1)==1) {
718 		if (linebuf[i] == '\n') {
719 			/* Don't rely on newline mode, assume raw */
720 			linebuf[i++] = '\r';
721 			linebuf[i++] = '\n';
722 			linebuf[i] = '\0';
723 			return linebuf;
724 		}
725 		++i;
726 	}
727 	linebuf[i] = '\0';
728 	return i ? linebuf : 0;
729 }
730 
731 static void
732 putf(const char *cp)
733 {
734 	extern char editedhost[];
735 	time_t t;
736 	char *slash, db[100];
737 
738 	static struct utsname kerninfo;
739 
740 	if (!*kerninfo.sysname)
741 		uname(&kerninfo);
742 
743 	while (*cp) {
744 		if (*cp != '%') {
745 			putchr(*cp++);
746 			continue;
747 		}
748 		switch (*++cp) {
749 
750 		case 't':
751 			slash = strrchr(ttyn, '/');
752 			if (slash == (char *) 0)
753 				puts(ttyn);
754 			else
755 				puts(&slash[1]);
756 			break;
757 
758 		case 'h':
759 			puts(editedhost);
760 			break;
761 
762 		case 'd': {
763 			t = (time_t)0;
764 			(void)time(&t);
765 			if (Lo)
766 				(void)setlocale(LC_TIME, Lo);
767 			(void)strftime(db, sizeof(db), DF, localtime(&t));
768 			puts(db);
769 			break;
770 
771 		case 's':
772 			puts(kerninfo.sysname);
773 			break;
774 
775 		case 'm':
776 			puts(kerninfo.machine);
777 			break;
778 
779 		case 'r':
780 			puts(kerninfo.release);
781 			break;
782 
783 		case 'v':
784 			puts(kerninfo.version);
785 			break;
786 		}
787 
788 		case '%':
789 			putchr('%');
790 			break;
791 		}
792 		cp++;
793 	}
794 }
795 
796 /*
797  * Read a gettytab database entry and perform necessary quirks.
798  */
799 static void
800 dogettytab(void)
801 {
802 
803 	/* Read the database entry. */
804 	gettable(tname, tabent);
805 
806 	/*
807 	 * Avoid inheriting the parity values from the default entry
808 	 * if any of them is set in the current entry.
809 	 * Mixing different parity settings is unreasonable.
810 	 */
811 	if (OPset || EPset || APset || NPset)
812 		OPset = EPset = APset = NPset = 1;
813 
814 	/* Fill in default values for unset capabilities. */
815 	setdefaults();
816 }
817