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