1/*
2 * Copyright (c) 1983, 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#if 0
36static char sccsid[] = "@(#)from: subr.c	8.1 (Berkeley) 6/4/93";
37#endif
38static const char rcsid[] =
39  "$FreeBSD: src/libexec/getty/subr.c,v 1.19 2004/06/25 10:11:28 phk Exp $";
40#endif /* not lint */
41
42/*
43 * Melbourne getty.
44 */
45#ifdef DEBUG
46#include <stdio.h>
47#endif
48#include <stdlib.h>
49#include <string.h>
50#include <termios.h>
51#include <unistd.h>
52#include <sys/ioctl.h>
53#include <sys/param.h>
54#include <sys/time.h>
55#include <syslog.h>
56
57#include "gettytab.h"
58#include "pathnames.h"
59#include "extern.h"
60
61
62
63/*
64 * Get a table entry.
65 */
66void
67gettable(const char *name)
68{
69	char *buf = NULL;
70	struct gettystrs *sp;
71	struct gettynums *np;
72	struct gettyflags *fp;
73	long n;
74	int l;
75	char *p;
76	char *msg = NULL;
77	const char *dba[2];
78
79	static int firsttime = 1;
80
81	dba[0] = _PATH_GETTYTAB;
82	dba[1] = 0;
83
84	if (firsttime) {
85		/*
86		 * we need to strdup() anything in the strings array
87		 * initially in order to simplify things later
88		 */
89		for (sp = gettystrs; sp->field; sp++)
90			if (sp->value != NULL) {
91				/* handle these ones more carefully */
92				if (sp >= &gettystrs[4] && sp <= &gettystrs[6])
93					l = 2;
94				else
95					l = (int)strlen(sp->value) + 1;
96				if ((p = malloc(l)) != NULL) {
97					strncpy(p, sp->value, l);
98					p[l-1] = '\0';
99				}
100				/*
101				 * replace, even if NULL, else we'll
102				 * have problems with free()ing static mem
103				 */
104				sp->value = p;
105			}
106		firsttime = 0;
107	}
108
109	switch (cgetent(&buf, (char **)dba, (char *)name)) {
110	case 1:
111		msg = "%s: couldn't resolve 'tc=' in gettytab '%s'";
112	case 0:
113		break;
114	case -1:
115		msg = "%s: unknown gettytab entry '%s'";
116		break;
117	case -2:
118		msg = "%s: retrieving gettytab entry '%s': %m";
119		break;
120	case -3:
121		msg = "%s: recursive 'tc=' reference gettytab entry '%s'";
122		break;
123	default:
124		msg = "%s: unexpected cgetent() error for entry '%s'";
125		break;
126	}
127
128	if (msg != NULL) {
129		syslog(LOG_ERR, msg, "getty", name);
130		return;
131	}
132
133	for (sp = gettystrs; sp->field; sp++) {
134		if ((l = cgetstr(buf, (char*)sp->field, &p)) >= 0) {
135			if (sp->value) {
136				/* prefer existing value */
137				if (strcmp(p, sp->value) != 0)
138					free(sp->value);
139				else {
140					free(p);
141					p = sp->value;
142				}
143			}
144			sp->value = p;
145		} else if (l == -1) {
146			free(sp->value);
147			sp->value = NULL;
148		}
149	}
150
151	for (np = gettynums; np->field; np++) {
152		if (cgetnum(buf, (char*)np->field, &n) == -1)
153			np->set = 0;
154		else {
155			np->set = 1;
156			np->value = n;
157		}
158	}
159
160	for (fp = gettyflags; fp->field; fp++) {
161		if (cgetcap(buf, (char *)fp->field, ':') == NULL)
162			fp->set = 0;
163		else {
164			fp->set = 1;
165			fp->value = 1 ^ fp->invrt;
166		}
167	}
168
169#ifdef DEBUG
170	printf("name=\"%s\", buf=\"%s\"\r\n", name, buf);
171	for (sp = gettystrs; sp->field; sp++)
172		printf("cgetstr: %s=%s\r\n", sp->field, sp->value);
173	for (np = gettynums; np->field; np++)
174		printf("cgetnum: %s=%d\r\n", np->field, np->value);
175	for (fp = gettyflags; fp->field; fp++)
176		printf("cgetflags: %s='%c' set='%c'\r\n", fp->field,
177		       fp->value + '0', fp->set + '0');
178#endif /* DEBUG */
179
180	free(buf);
181}
182
183void
184gendefaults(void)
185{
186	struct gettystrs *sp;
187	struct gettynums *np;
188	struct gettyflags *fp;
189
190	for (sp = gettystrs; sp->field; sp++)
191		if (sp->value)
192			sp->defalt = strdup(sp->value);
193	for (np = gettynums; np->field; np++)
194		if (np->set)
195			np->defalt = np->value;
196	for (fp = gettyflags; fp->field; fp++)
197		if (fp->set)
198			fp->defalt = fp->value;
199		else
200			fp->defalt = fp->invrt;
201}
202
203void
204setdefaults(void)
205{
206	struct gettystrs *sp;
207	struct gettynums *np;
208	struct gettyflags *fp;
209
210	for (sp = gettystrs; sp->field; sp++)
211		if (!sp->value)
212			sp->value = !sp->defalt ? sp->defalt
213						: strdup(sp->defalt);
214	for (np = gettynums; np->field; np++)
215		if (!np->set)
216			np->value = np->defalt;
217	for (fp = gettyflags; fp->field; fp++)
218		if (!fp->set)
219			fp->value = fp->defalt;
220}
221
222static char **
223charnames[] = {
224	&ER, &KL, &IN, &QU, &XN, &XF, &ET, &BK,
225	&SU, &DS, &RP, &FL, &WE, &LN, 0
226};
227
228static char *
229charvars[] = {
230	(char*)&tmode.c_cc[VERASE],
231	(char*)&tmode.c_cc[VKILL],
232	(char*)&tmode.c_cc[VINTR],
233	(char*)&tmode.c_cc[VQUIT],
234	(char*)&tmode.c_cc[VSTART],
235	(char*)&tmode.c_cc[VSTOP],
236	(char*)&tmode.c_cc[VEOF],
237	(char*)&tmode.c_cc[VEOL],
238	(char*)&tmode.c_cc[VSUSP],
239	(char*)&tmode.c_cc[VDSUSP],
240	(char*)&tmode.c_cc[VREPRINT],
241	(char*)&tmode.c_cc[VDISCARD],
242	(char*)&tmode.c_cc[VWERASE],
243	(char*)&tmode.c_cc[VLNEXT],
244	0
245};
246
247void
248setchars(void)
249{
250	int i;
251	const char *p;
252
253	for (i = 0; charnames[i]; i++) {
254		p = *charnames[i];
255		if (p && *p)
256			*charvars[i] = *p;
257		else
258			*charvars[i] = _POSIX_VDISABLE;
259	}
260}
261
262/* Macros to clear/set/test flags. */
263#define	SET(t, f)	(t) |= (f)
264#define	CLR(t, f)	(t) &= ~(f)
265#define	ISSET(t, f)	((t) & (f))
266
267void
268set_flags(int n)
269{
270	tcflag_t iflag, oflag, cflag, lflag;
271
272
273	switch (n) {
274	case 0:
275		if (C0set && I0set && L0set && O0set) {
276			tmode.c_cflag = C0;
277			tmode.c_iflag = I0;
278			tmode.c_lflag = L0;
279			tmode.c_oflag = O0;
280			return;
281		}
282		break;
283	case 1:
284		if (C1set && I1set && L1set && O1set) {
285			tmode.c_cflag = C1;
286			tmode.c_iflag = I1;
287			tmode.c_lflag = L1;
288			tmode.c_oflag = O1;
289			return;
290		}
291		break;
292	default:
293		if (C2set && I2set && L2set && O2set) {
294			tmode.c_cflag = C2;
295			tmode.c_iflag = I2;
296			tmode.c_lflag = L2;
297			tmode.c_oflag = O2;
298			return;
299		}
300		break;
301	}
302
303	iflag = omode.c_iflag;
304	oflag = omode.c_oflag;
305	cflag = omode.c_cflag;
306	lflag = omode.c_lflag;
307
308	if (NP) {
309		CLR(cflag, CSIZE|PARENB);
310		SET(cflag, CS8);
311		CLR(iflag, ISTRIP|INPCK|IGNPAR);
312	} else if (AP || EP || OP) {
313		CLR(cflag, CSIZE);
314		SET(cflag, CS7|PARENB);
315		SET(iflag, ISTRIP);
316		if (OP && !EP) {
317			SET(iflag, INPCK|IGNPAR);
318			SET(cflag, PARODD);
319			if (AP)
320				CLR(iflag, INPCK);
321		} else if (EP && !OP) {
322			SET(iflag, INPCK|IGNPAR);
323			CLR(cflag, PARODD);
324			if (AP)
325				CLR(iflag, INPCK);
326		} else if (AP || (EP && OP)) {
327			CLR(iflag, INPCK|IGNPAR);
328			CLR(cflag, PARODD);
329		}
330	} /* else, leave as is */
331
332#if 0
333	if (UC)
334		f |= LCASE;
335#endif
336
337	if (HC)
338		SET(cflag, HUPCL);
339	else
340		CLR(cflag, HUPCL);
341
342	if (MB)
343		SET(cflag, MDMBUF);
344	else
345		CLR(cflag, MDMBUF);
346
347	if (HW)
348		SET(cflag, CRTSCTS);
349	else
350		CLR(cflag, CRTSCTS);
351
352	if (NL) {
353		SET(iflag, ICRNL);
354		SET(oflag, ONLCR|OPOST);
355	} else {
356		CLR(iflag, ICRNL);
357		CLR(oflag, ONLCR);
358	}
359
360	if (!HT)
361		SET(oflag, OXTABS|OPOST);
362	else
363		CLR(oflag, OXTABS);
364
365#ifdef XXX_DELAY
366	SET(f, delaybits());
367#endif
368
369	if (n == 1) {		/* read mode flags */
370		if (RW) {
371			iflag = 0;
372			CLR(oflag, OPOST);
373			CLR(cflag, CSIZE|PARENB);
374			SET(cflag, CS8);
375			lflag = 0;
376		} else {
377			CLR(lflag, ICANON);
378		}
379		goto out;
380	}
381
382	if (n == 0)
383		goto out;
384
385#if 0
386	if (CB)
387		SET(f, CRTBS);
388#endif
389
390	if (CE)
391		SET(lflag, ECHOE);
392	else
393		CLR(lflag, ECHOE);
394
395	if (CK)
396		SET(lflag, ECHOKE);
397	else
398		CLR(lflag, ECHOKE);
399
400	if (PE)
401		SET(lflag, ECHOPRT);
402	else
403		CLR(lflag, ECHOPRT);
404
405	if (EC)
406		SET(lflag, ECHO);
407	else
408		CLR(lflag, ECHO);
409
410	if (XC)
411		SET(lflag, ECHOCTL);
412	else
413		CLR(lflag, ECHOCTL);
414
415	if (DX)
416		SET(lflag, IXANY);
417	else
418		CLR(lflag, IXANY);
419
420out:
421	tmode.c_iflag = iflag;
422	tmode.c_oflag = oflag;
423	tmode.c_cflag = cflag;
424	tmode.c_lflag = lflag;
425}
426
427
428#ifdef XXX_DELAY
429struct delayval {
430	unsigned	delay;		/* delay in ms */
431	int		bits;
432};
433
434/*
435 * below are random guesses, I can't be bothered checking
436 */
437
438struct delayval	crdelay[] = {
439	{ 1,		CR1 },
440	{ 2,		CR2 },
441	{ 3,		CR3 },
442	{ 83,		CR1 },
443	{ 166,		CR2 },
444	{ 0,		CR3 },
445};
446
447struct delayval nldelay[] = {
448	{ 1,		NL1 },		/* special, calculated */
449	{ 2,		NL2 },
450	{ 3,		NL3 },
451	{ 100,		NL2 },
452	{ 0,		NL3 },
453};
454
455struct delayval	bsdelay[] = {
456	{ 1,		BS1 },
457	{ 0,		0 },
458};
459
460struct delayval	ffdelay[] = {
461	{ 1,		FF1 },
462	{ 1750,		FF1 },
463	{ 0,		FF1 },
464};
465
466struct delayval	tbdelay[] = {
467	{ 1,		TAB1 },
468	{ 2,		TAB2 },
469	{ 3,		XTABS },	/* this is expand tabs */
470	{ 100,		TAB1 },
471	{ 0,		TAB2 },
472};
473
474int
475delaybits(void)
476{
477	int f;
478
479	f  = adelay(CD, crdelay);
480	f |= adelay(ND, nldelay);
481	f |= adelay(FD, ffdelay);
482	f |= adelay(TD, tbdelay);
483	f |= adelay(BD, bsdelay);
484	return (f);
485}
486
487int
488adelay(int ms, struct delayval *dp)
489{
490	if (ms == 0)
491		return (0);
492	while (dp->delay && ms > dp->delay)
493		dp++;
494	return (dp->bits);
495}
496#endif
497
498char	editedhost[MAXHOSTNAMELEN];
499
500void
501edithost(const char *pat)
502{
503	const char *host = HN;
504	char *res = editedhost;
505
506	if (!pat)
507		pat = "";
508	while (*pat) {
509		switch (*pat) {
510
511		case '#':
512			if (*host)
513				host++;
514			break;
515
516		case '@':
517			if (*host)
518				*res++ = *host++;
519			break;
520
521		default:
522			*res++ = *pat;
523			break;
524
525		}
526		if (res == &editedhost[sizeof editedhost - 1]) {
527			*res = '\0';
528			return;
529		}
530		pat++;
531	}
532	if (*host)
533		strncpy(res, host, sizeof editedhost - (res - editedhost) - 1);
534	else
535		*res = '\0';
536	editedhost[sizeof editedhost - 1] = '\0';
537}
538
539static struct speedtab {
540	int	speed;
541	int	uxname;
542} speedtab[] = {
543	{ 50,	B50 },
544	{ 75,	B75 },
545	{ 110,	B110 },
546	{ 134,	B134 },
547	{ 150,	B150 },
548	{ 200,	B200 },
549	{ 300,	B300 },
550	{ 600,	B600 },
551	{ 1200,	B1200 },
552	{ 1800,	B1800 },
553	{ 2400,	B2400 },
554	{ 4800,	B4800 },
555	{ 9600,	B9600 },
556	{ 19200, EXTA },
557	{ 19,	EXTA },		/* for people who say 19.2K */
558	{ 38400, EXTB },
559	{ 38,	EXTB },
560	{ 7200,	EXTB },		/* alternative */
561	{ 57600, B57600 },
562	{ 115200, B115200 },
563	{ 230400, B230400 },
564	{ 0 }
565};
566
567int
568speed(int val)
569{
570	struct speedtab *sp;
571
572	if (val <= B230400)
573		return (val);
574
575	for (sp = speedtab; sp->speed; sp++)
576		if (sp->speed == val)
577			return (sp->uxname);
578
579	return (B300);		/* default in impossible cases */
580}
581
582void
583makeenv(char *env[])
584{
585	static char termbuf[128] = "TERM=";
586	char *p, *q;
587	char **ep;
588
589	ep = env;
590	if (TT && *TT) {
591		strlcat(termbuf, TT, sizeof(termbuf));
592		*ep++ = termbuf;
593	}
594	if ((p = EV)) {
595		q = p;
596		while ((q = strchr(q, ','))) {
597			*q++ = '\0';
598			*ep++ = p;
599			p = q;
600		}
601		if (*p)
602			*ep++ = p;
603	}
604	*ep = (char *)0;
605}
606
607/*
608 * This speed select mechanism is written for the Develcon DATASWITCH.
609 * The Develcon sends a string of the form "B{speed}\n" at a predefined
610 * baud rate. This string indicates the user's actual speed.
611 * The routine below returns the terminal type mapped from derived speed.
612 */
613struct	portselect {
614	const char	*ps_baud;
615	const char	*ps_type;
616} portspeeds[] = {
617	{ "B110",	"std.110" },
618	{ "B134",	"std.134" },
619	{ "B150",	"std.150" },
620	{ "B300",	"std.300" },
621	{ "B600",	"std.600" },
622	{ "B1200",	"std.1200" },
623	{ "B2400",	"std.2400" },
624	{ "B4800",	"std.4800" },
625	{ "B9600",	"std.9600" },
626	{ "B19200",	"std.19200" },
627	{ 0 }
628};
629
630const char *
631portselector(void)
632{
633	char c, baud[20];
634	const char *type = "default";
635	struct portselect *ps;
636	int len;
637
638	alarm(5*60);
639	for (len = 0; len < sizeof (baud) - 1; len++) {
640		if (read(STDIN_FILENO, &c, 1) <= 0)
641			break;
642		c &= 0177;
643		if (c == '\n' || c == '\r')
644			break;
645		if (c == 'B')
646			len = 0;	/* in case of leading garbage */
647		baud[len] = c;
648	}
649	baud[len] = '\0';
650	for (ps = portspeeds; ps->ps_baud; ps++)
651		if (strcmp(ps->ps_baud, baud) == 0) {
652			type = ps->ps_type;
653			break;
654		}
655	sleep(2);	/* wait for connection to complete */
656	return (type);
657}
658
659/*
660 * This auto-baud speed select mechanism is written for the Micom 600
661 * portselector. Selection is done by looking at how the character '\r'
662 * is garbled at the different speeds.
663 */
664const char *
665autobaud(void)
666{
667	int rfds;
668	struct timeval timeout;
669	char c;
670	const char *type = "9600-baud";
671
672	(void)tcflush(0, TCIOFLUSH);
673	rfds = 1 << 0;
674	timeout.tv_sec = 5;
675	timeout.tv_usec = 0;
676	if (select(32, (fd_set *)&rfds, (fd_set *)NULL,
677	    (fd_set *)NULL, &timeout) <= 0)
678		return (type);
679	if (read(STDIN_FILENO, &c, sizeof(char)) != sizeof(char))
680		return (type);
681	timeout.tv_sec = 0;
682	timeout.tv_usec = 20;
683	(void) select(32, (fd_set *)NULL, (fd_set *)NULL,
684	    (fd_set *)NULL, &timeout);
685	(void)tcflush(0, TCIOFLUSH);
686	switch (c & 0377) {
687
688	case 0200:		/* 300-baud */
689		type = "300-baud";
690		break;
691
692	case 0346:		/* 1200-baud */
693		type = "1200-baud";
694		break;
695
696	case  015:		/* 2400-baud */
697	case 0215:
698		type = "2400-baud";
699		break;
700
701	default:		/* 4800-baud */
702		type = "4800-baud";
703		break;
704
705	case 0377:		/* 9600-baud */
706		type = "9600-baud";
707		break;
708	}
709	return (type);
710}
711