xref: /freebsd/libexec/getty/main.c (revision 5b31cc94b10d4bb7109c6b27940a0fc76a44a331)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
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 #ifndef lint
33 static const char copyright[] =
34 "@(#) Copyright (c) 1980, 1993\n\
35 	The Regents of the University of California.  All rights reserved.\n";
36 #endif /* not lint */
37 
38 #ifndef lint
39 #endif /* not lint */
40 #include <sys/cdefs.h>
41 #include <sys/param.h>
42 #include <sys/ioctl.h>
43 #include <sys/time.h>
44 #include <sys/resource.h>
45 #include <sys/stat.h>
46 #include <sys/ttydefaults.h>
47 #include <sys/utsname.h>
48 
49 #include <ctype.h>
50 #include <errno.h>
51 #include <fcntl.h>
52 #include <locale.h>
53 #include <libutil.h>
54 #include <setjmp.h>
55 #include <signal.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <syslog.h>
60 #include <termios.h>
61 #include <time.h>
62 #include <unistd.h>
63 
64 #include "gettytab.h"
65 #include "extern.h"
66 #include "pathnames.h"
67 
68 /*
69  * Set the amount of running time that getty should accumulate
70  * before deciding that something is wrong and exit.
71  */
72 #define GETTY_TIMEOUT	60 /* seconds */
73 
74 #undef CTRL
75 #define CTRL(x)  (x&037)
76 
77 /* defines for auto detection of incoming PPP calls (->PAP/CHAP) */
78 
79 #define PPP_FRAME           0x7e  /* PPP Framing character */
80 #define PPP_STATION         0xff  /* "All Station" character */
81 #define PPP_ESCAPE          0x7d  /* Escape Character */
82 #define PPP_CONTROL         0x03  /* PPP Control Field */
83 #define PPP_CONTROL_ESCAPED 0x23  /* PPP Control Field, escaped */
84 #define PPP_LCP_HI          0xc0  /* LCP protocol - high byte */
85 #define PPP_LCP_LOW         0x21  /* LCP protocol - low byte */
86 
87 /* original mode; flags've been reset using values from <sys/ttydefaults.h> */
88 struct termios omode;
89 /* current mode */
90 struct termios tmode;
91 
92 static int crmod, digit, lower, upper;
93 
94 char	hostname[MAXHOSTNAMELEN];
95 static char	name[MAXLOGNAME*3];
96 static char	ttyn[32];
97 
98 #define	OBUFSIZ		128
99 
100 static const char	*tname;
101 
102 static char	*env[128];
103 
104 static char partab[] = {
105 	0001,0201,0201,0001,0201,0001,0001,0201,
106 	0202,0004,0003,0205,0005,0206,0201,0001,
107 	0201,0001,0001,0201,0001,0201,0201,0001,
108 	0001,0201,0201,0001,0201,0001,0001,0201,
109 	0200,0000,0000,0200,0000,0200,0200,0000,
110 	0000,0200,0200,0000,0200,0000,0000,0200,
111 	0000,0200,0200,0000,0200,0000,0000,0200,
112 	0200,0000,0000,0200,0000,0200,0200,0000,
113 	0200,0000,0000,0200,0000,0200,0200,0000,
114 	0000,0200,0200,0000,0200,0000,0000,0200,
115 	0000,0200,0200,0000,0200,0000,0000,0200,
116 	0200,0000,0000,0200,0000,0200,0200,0000,
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,0201
121 };
122 
123 #define	ERASE	tmode.c_cc[VERASE]
124 #define	KILL	tmode.c_cc[VKILL]
125 #define	EOT	tmode.c_cc[VEOF]
126 
127 #define	puts	Gputs
128 
129 static void	defttymode(void);
130 static void	dingdong(int);
131 static void	dogettytab(void);
132 static int	getname(void);
133 static void	interrupt(int);
134 static void	oflush(void);
135 static void	prompt(void);
136 static void	putchr(int);
137 static void	putf(const char *);
138 static void	putpad(const char *);
139 static void	puts(const char *);
140 static void	timeoverrun(int);
141 static char	*get_line(int);
142 static void	setttymode(int);
143 static int	opentty(const char *, int);
144 
145 static jmp_buf timeout;
146 
147 static void
148 dingdong(int signo __unused)
149 {
150 	alarm(0);
151 	longjmp(timeout, 1);
152 }
153 
154 static jmp_buf	intrupt;
155 
156 static void
157 interrupt(int signo __unused)
158 {
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 __unused)
167 {
168 
169 	syslog(LOG_ERR, "getty exiting due to excessive running time");
170 	exit(1);
171 }
172 
173 int
174 main(int argc, char *argv[])
175 {
176 	int first_sleep = 1, first_time = 1;
177 	struct rlimit limit;
178 	int rval;
179 
180 	signal(SIGINT, SIG_IGN);
181 	signal(SIGQUIT, SIG_IGN);
182 
183 	openlog("getty", LOG_CONS|LOG_PID, LOG_AUTH);
184 	gethostname(hostname, sizeof(hostname) - 1);
185 	hostname[sizeof(hostname) - 1] = '\0';
186 	if (hostname[0] == '\0')
187 		snprintf(hostname, sizeof(hostname), "Amnesiac");
188 
189 	/*
190 	 * Limit running time to deal with broken or dead lines.
191 	 */
192 	(void)signal(SIGXCPU, timeoverrun);
193 	limit.rlim_max = RLIM_INFINITY;
194 	limit.rlim_cur = GETTY_TIMEOUT;
195 	(void)setrlimit(RLIMIT_CPU, &limit);
196 
197 	gettable("default");
198 	gendefaults();
199 	tname = "default";
200 	if (argc > 1)
201 		tname = argv[1];
202 
203 	/*
204 	 * The following is a work around for vhangup interactions
205 	 * which cause great problems getting window systems started.
206 	 * If the tty line is "-", we do the old style getty presuming
207 	 * that the file descriptors are already set up for us.
208 	 * J. Gettys - MIT Project Athena.
209 	 */
210 	if (argc <= 2 || strcmp(argv[2], "-") == 0) {
211 		char *n = ttyname(STDIN_FILENO);
212 		if (n == NULL) {
213 			syslog(LOG_ERR, "ttyname: %m");
214 			exit(1);
215 		}
216 		snprintf(ttyn, sizeof(ttyn), "%s", n);
217 	} else {
218 		snprintf(ttyn, sizeof(ttyn), "%s%s", _PATH_DEV, argv[2]);
219 		if (strcmp(argv[0], "+") != 0) {
220 			chown(ttyn, 0, 0);
221 			chmod(ttyn, 0600);
222 			revoke(ttyn);
223 
224 			/*
225 			 * Do the first scan through gettytab.
226 			 * Terminal mode parameters will be wrong until
227 			 * defttymode() called, but they're irrelevant for
228 			 * the initial setup of the terminal device.
229 			 */
230 			dogettytab();
231 
232 			/*
233 			 * Init or answer modem sequence has been specified.
234 			 */
235 			if (IC || AC) {
236 				if (!opentty(ttyn, O_RDWR|O_NONBLOCK))
237 					exit(1);
238 				defttymode();
239 				setttymode(1);
240 			}
241 
242 			if (IC) {
243 				if (getty_chat(IC, CT, DC) > 0) {
244 					syslog(LOG_ERR, "modem init problem on %s", ttyn);
245 					(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
246 					exit(1);
247 				}
248 			}
249 
250 			if (AC) {
251 				fd_set rfds;
252 				struct timeval to;
253 				int i;
254 
255 				FD_ZERO(&rfds);
256 				FD_SET(0, &rfds);
257 				to.tv_sec = RT;
258 				to.tv_usec = 0;
259 				i = select(32, &rfds, NULL, NULL, RT ? &to : NULL);
260 				if (i < 0) {
261 					syslog(LOG_ERR, "select %s: %m", ttyn);
262 				} else if (i == 0) {
263 					syslog(LOG_NOTICE, "recycle tty %s", ttyn);
264 					(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
265 					exit(0);  /* recycle for init */
266 				}
267 				i = getty_chat(AC, CT, DC);
268 				if (i > 0) {
269 					syslog(LOG_ERR, "modem answer problem on %s", ttyn);
270 					(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
271 					exit(1);
272 				}
273 			} else { /* maybe blocking open */
274 				if (!opentty(ttyn, O_RDWR | (NC ? O_NONBLOCK : 0 )))
275 					exit(1);
276 			}
277 		}
278 	}
279 
280 	defttymode();
281 	for (;;) {
282 
283 		/*
284 		 * if a delay was specified then sleep for that
285 		 * number of seconds before writing the initial prompt
286 		 */
287 		if (first_sleep && DE) {
288 			sleep(DE);
289 			/* remove any noise */
290 			(void)tcflush(STDIN_FILENO, TCIOFLUSH);
291 		}
292 		first_sleep = 0;
293 
294 		setttymode(0);
295 		if (AB) {
296 			tname = autobaud();
297 			dogettytab();
298 			continue;
299 		}
300 		if (PS) {
301 			tname = portselector();
302 			dogettytab();
303 			continue;
304 		}
305 		if (CL && *CL)
306 			putpad(CL);
307 		edithost(HE);
308 
309 		/* if this is the first time through this, and an
310 		   issue file has been given, then send it */
311 		if (first_time && IF) {
312 			int fd;
313 
314 			if ((fd = open(IF, O_RDONLY)) != -1) {
315 				char * cp;
316 
317 				while ((cp = get_line(fd)) != NULL) {
318 					putf(cp);
319 				}
320 				close(fd);
321 			}
322 		}
323 		first_time = 0;
324 
325 		if (IMP && *IMP && !(PL && PP))
326 			system(IMP);
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 failopenlogged = 0, i, saved_errno;
427 
428 	while ((i = open(tty, flags)) == -1)
429 	{
430 		saved_errno = errno;
431 		if (!failopenlogged) {
432 			syslog(LOG_ERR, "open %s: %m", tty);
433 			failopenlogged = 1;
434 		}
435 		if (saved_errno == ENOENT)
436 			return 0;
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 static char	outbuf[OBUFSIZ];
668 static 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 get_line(int fd)
709 {
710 	size_t 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 	time_t t;
735 	char db[100];
736 	const char *slash;
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 		case '%':
788 			putchr('%');
789 			break;
790 		}
791 		cp++;
792 	}
793 }
794 
795 /*
796  * Read a gettytab database entry and perform necessary quirks.
797  */
798 static void
799 dogettytab(void)
800 {
801 
802 	/* Read the database entry. */
803 	gettable(tname);
804 
805 	/*
806 	 * Avoid inheriting the parity values from the default entry
807 	 * if any of them is set in the current entry.
808 	 * Mixing different parity settings is unreasonable.
809 	 */
810 	if (OPset || EPset || APset || NPset)
811 		OPset = EPset = APset = NPset = 1;
812 
813 	/* Fill in default values for unset capabilities. */
814 	setdefaults();
815 }
816