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