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