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