subr.c revision 31331
1145436Sdavidxu/*
2145436Sdavidxu * Copyright (c) 1983, 1993
3145436Sdavidxu *	The Regents of the University of California.  All rights reserved.
4212516Simp *
5212516Simp * Redistribution and use in source and binary forms, with or without
6212516Simp * modification, are permitted provided that the following conditions
7212516Simp * are met:
8145436Sdavidxu * 1. Redistributions of source code must retain the above copyright
9145436Sdavidxu *    notice, this list of conditions and the following disclaimer.
10212516Simp * 2. Redistributions in binary form must reproduce the above copyright
11212516Simp *    notice, this list of conditions and the following disclaimer in the
12212516Simp *    documentation and/or other materials provided with the distribution.
13212516Simp * 3. All advertising materials mentioning features or use of this software
14145436Sdavidxu *    must display the following acknowledgement:
15145436Sdavidxu *	This product includes software developed by the University of
16145436Sdavidxu *	California, Berkeley and its contributors.
17145436Sdavidxu * 4. Neither the name of the University nor the names of its contributors
18145436Sdavidxu *    may be used to endorse or promote products derived from this software
19145436Sdavidxu *    without specific prior written permission.
20145436Sdavidxu *
21145436Sdavidxu * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22145436Sdavidxu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23145436Sdavidxu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24145436Sdavidxu * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25145436Sdavidxu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26145436Sdavidxu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27145436Sdavidxu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28145436Sdavidxu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29145436Sdavidxu * 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	"$Id$";
40#endif /* not lint */
41
42/*
43 * Melbourne getty.
44 */
45#define COMPAT_43
46#ifdef DEBUG
47#include <stdio.h>
48#endif
49#include <stdlib.h>
50#include <string.h>
51#include <termios.h>
52#include <unistd.h>
53#include <sys/ioctl.h>
54#include <sys/param.h>
55#include <sys/time.h>
56#include <syslog.h>
57
58#include "gettytab.h"
59#include "pathnames.h"
60#include "extern.h"
61
62
63#ifdef COMPAT_43
64static void	compatflags __P((long));
65#endif
66
67/*
68 * Get a table entry.
69 */
70void
71gettable(name, buf)
72	const char *name;
73	char *buf;
74{
75	register struct gettystrs *sp;
76	register struct gettynums *np;
77	register struct gettyflags *fp;
78	long n;
79	int l;
80	char *p;
81	char *msg = NULL;
82	const char *dba[2];
83
84	static int firsttime = 1;
85
86	dba[0] = _PATH_GETTYTAB;
87	dba[1] = 0;
88
89	if (firsttime) {
90		/*
91		 * we need to strdup() anything in the strings array
92		 * initially in order to simplify things later
93		 */
94		for (sp = gettystrs; sp->field; sp++)
95			if (sp->value != NULL) {
96				/* handle these ones more carefully */
97				if (sp >= &gettystrs[4] && sp <= &gettystrs[6])
98					l = 2;
99				else
100					l = strlen(sp->value) + 1;
101				if ((p = malloc(l)) != NULL) {
102					strncpy(p, sp->value, l);
103					p[l-1] = '\0';
104				}
105				/*
106				 * replace, even if NULL, else we'll
107				 * have problems with free()ing static mem
108				 */
109				sp->value = p;
110			}
111		firsttime = 0;
112	}
113
114	switch (cgetent(&buf, (char **)dba, (char *)name)) {
115	case 1:
116		msg = "%s: couldn't resolve 'tc=' in gettytab '%s'";
117	case 0:
118		break;
119	case -1:
120		msg = "%s: unknown gettytab entry '%s'";
121		break;
122	case -2:
123		msg = "%s: retrieving gettytab entry '%s': %m";
124		break;
125	case -3:
126		msg = "%s: recursive 'tc=' reference gettytab entry '%s'";
127		break;
128	default:
129		msg = "%s: unexpected cgetent() error for entry '%s'";
130		break;
131	}
132
133	if (msg != NULL) {
134		syslog(LOG_ERR, msg, "getty", name);
135		return;
136	}
137
138	for (sp = gettystrs; sp->field; sp++) {
139		if ((l = cgetstr(buf, (char*)sp->field, &p)) >= 0) {
140			if (sp->value) {
141				/* prefer existing value */
142				if (strcmp(p, sp->value) != 0)
143					free(sp->value);
144				else {
145					free(p);
146					p = sp->value;
147				}
148			}
149			sp->value = p;
150		} else if (l == -1) {
151			free(sp->value);
152			sp->value = NULL;
153		}
154	}
155
156	for (np = gettynums; np->field; np++) {
157		if (cgetnum(buf, (char*)np->field, &n) == -1)
158			np->set = 0;
159		else {
160			np->set = 1;
161			np->value = n;
162		}
163	}
164
165	for (fp = gettyflags; fp->field; fp++) {
166		if (cgetcap(buf, (char *)fp->field, ':') == NULL)
167			fp->set = 0;
168		else {
169			fp->set = 1;
170			fp->value = 1 ^ fp->invrt;
171		}
172	}
173
174#ifdef DEBUG
175	printf("name=\"%s\", buf=\"%s\"\r\n", name, buf);
176	for (sp = gettystrs; sp->field; sp++)
177		printf("cgetstr: %s=%s\r\n", sp->field, sp->value);
178	for (np = gettynums; np->field; np++)
179		printf("cgetnum: %s=%d\r\n", np->field, np->value);
180	for (fp = gettyflags; fp->field; fp++)
181		printf("cgetflags: %s='%c' set='%c'\r\n", fp->field,
182		       fp->value + '0', fp->set + '0');
183#endif /* DEBUG */
184}
185
186void
187gendefaults()
188{
189	register struct gettystrs *sp;
190	register struct gettynums *np;
191	register struct gettyflags *fp;
192
193	for (sp = gettystrs; sp->field; sp++)
194		if (sp->value)
195			sp->defalt = strdup(sp->value);
196	for (np = gettynums; np->field; np++)
197		if (np->set)
198			np->defalt = np->value;
199	for (fp = gettyflags; fp->field; fp++)
200		if (fp->set)
201			fp->defalt = fp->value;
202		else
203			fp->defalt = fp->invrt;
204}
205
206void
207setdefaults()
208{
209	register struct gettystrs *sp;
210	register struct gettynums *np;
211	register struct gettyflags *fp;
212
213	for (sp = gettystrs; sp->field; sp++)
214		if (!sp->value)
215			sp->value = !sp->defalt ? sp->defalt
216						: strdup(sp->defalt);
217	for (np = gettynums; np->field; np++)
218		if (!np->set)
219			np->value = np->defalt;
220	for (fp = gettyflags; fp->field; fp++)
221		if (!fp->set)
222			fp->value = fp->defalt;
223}
224
225static char **
226charnames[] = {
227	&ER, &KL, &IN, &QU, &XN, &XF, &ET, &BK,
228	&SU, &DS, &RP, &FL, &WE, &LN, 0
229};
230
231static char *
232charvars[] = {
233	&tmode.c_cc[VERASE], &tmode.c_cc[VKILL], &tmode.c_cc[VINTR],
234	&tmode.c_cc[VQUIT], &tmode.c_cc[VSTART], &tmode.c_cc[VSTOP],
235	&tmode.c_cc[VEOF], &tmode.c_cc[VEOL], &tmode.c_cc[VSUSP],
236	&tmode.c_cc[VDSUSP], &tmode.c_cc[VREPRINT], &tmode.c_cc[VDISCARD],
237	&tmode.c_cc[VWERASE], &tmode.c_cc[VLNEXT], 0
238};
239
240void
241setchars()
242{
243	register int i;
244	register const char *p;
245
246	for (i = 0; charnames[i]; i++) {
247		p = *charnames[i];
248		if (p && *p)
249			*charvars[i] = *p;
250		else
251			*charvars[i] = _POSIX_VDISABLE;
252	}
253}
254
255/* Macros to clear/set/test flags. */
256#define	SET(t, f)	(t) |= (f)
257#define	CLR(t, f)	(t) &= ~(f)
258#define	ISSET(t, f)	((t) & (f))
259
260void
261setflags(n)
262	int n;
263{
264	register tcflag_t iflag, oflag, cflag, lflag;
265
266#ifdef COMPAT_43
267	switch (n) {
268	case 0:
269		if (F0set) {
270			compatflags(F0);
271			return;
272		}
273		break;
274	case 1:
275		if (F1set) {
276			compatflags(F1);
277			return;
278		}
279		break;
280	default:
281		if (F2set) {
282			compatflags(F2);
283			return;
284		}
285		break;
286	}
287#endif
288
289	switch (n) {
290	case 0:
291		if (C0set && I0set && L0set && O0set) {
292			tmode.c_cflag = C0;
293			tmode.c_iflag = I0;
294			tmode.c_lflag = L0;
295			tmode.c_oflag = O0;
296			return;
297		}
298		break;
299	case 1:
300		if (C1set && I1set && L1set && O1set) {
301			tmode.c_cflag = C1;
302			tmode.c_iflag = I1;
303			tmode.c_lflag = L1;
304			tmode.c_oflag = O1;
305			return;
306		}
307		break;
308	default:
309		if (C2set && I2set && L2set && O2set) {
310			tmode.c_cflag = C2;
311			tmode.c_iflag = I2;
312			tmode.c_lflag = L2;
313			tmode.c_oflag = O2;
314			return;
315		}
316		break;
317	}
318
319	iflag = omode.c_iflag;
320	oflag = omode.c_oflag;
321	cflag = omode.c_cflag;
322	lflag = omode.c_lflag;
323
324	if (NP) {
325		CLR(cflag, CSIZE|PARENB);
326		SET(cflag, CS8);
327		CLR(iflag, ISTRIP|INPCK|IGNPAR);
328	} else if (AP || EP || OP) {
329		CLR(cflag, CSIZE);
330		SET(cflag, CS7|PARENB);
331		SET(iflag, ISTRIP);
332		if (OP && !EP) {
333			SET(iflag, INPCK|IGNPAR);
334			SET(cflag, PARODD);
335			if (AP)
336				CLR(iflag, INPCK);
337		} else if (EP && !OP) {
338			SET(iflag, INPCK|IGNPAR);
339			CLR(cflag, PARODD);
340			if (AP)
341				CLR(iflag, INPCK);
342		} else if (AP || (EP && OP)) {
343			CLR(iflag, INPCK|IGNPAR);
344			CLR(cflag, PARODD);
345		}
346	} /* else, leave as is */
347
348#if 0
349	if (UC)
350		f |= LCASE;
351#endif
352
353	if (HC)
354		SET(cflag, HUPCL);
355	else
356		CLR(cflag, HUPCL);
357
358	if (MB)
359		SET(cflag, MDMBUF);
360	else
361		CLR(cflag, MDMBUF);
362
363	if (HW)
364		SET(cflag, CRTSCTS);
365	else
366		CLR(cflag, CRTSCTS);
367
368	if (NL) {
369		SET(iflag, ICRNL);
370		SET(oflag, ONLCR|OPOST);
371	} else {
372		CLR(iflag, ICRNL);
373		CLR(oflag, ONLCR);
374	}
375
376	if (!HT)
377		SET(oflag, OXTABS|OPOST);
378	else
379		CLR(oflag, OXTABS);
380
381#ifdef XXX_DELAY
382	SET(f, delaybits());
383#endif
384
385	if (n == 1) {		/* read mode flags */
386		if (RW) {
387			iflag = 0;
388			CLR(oflag, OPOST);
389			CLR(cflag, CSIZE|PARENB);
390			SET(cflag, CS8);
391			lflag = 0;
392		} else {
393			CLR(lflag, ICANON);
394		}
395		goto out;
396	}
397
398	if (n == 0)
399		goto out;
400
401#if 0
402	if (CB)
403		SET(f, CRTBS);
404#endif
405
406	if (CE)
407		SET(lflag, ECHOE);
408	else
409		CLR(lflag, ECHOE);
410
411	if (CK)
412		SET(lflag, ECHOKE);
413	else
414		CLR(lflag, ECHOKE);
415
416	if (PE)
417		SET(lflag, ECHOPRT);
418	else
419		CLR(lflag, ECHOPRT);
420
421	if (EC)
422		SET(lflag, ECHO);
423	else
424		CLR(lflag, ECHO);
425
426	if (XC)
427		SET(lflag, ECHOCTL);
428	else
429		CLR(lflag, ECHOCTL);
430
431	if (DX)
432		SET(lflag, IXANY);
433	else
434		CLR(lflag, IXANY);
435
436out:
437	tmode.c_iflag = iflag;
438	tmode.c_oflag = oflag;
439	tmode.c_cflag = cflag;
440	tmode.c_lflag = lflag;
441}
442
443#ifdef COMPAT_43
444/*
445 * Old TTY => termios, snatched from <sys/kern/tty_compat.c>
446 */
447void
448compatflags(flags)
449register long flags;
450{
451	register tcflag_t iflag, oflag, cflag, lflag;
452
453	iflag = BRKINT|ICRNL|IMAXBEL|IXON|IXANY;
454	oflag = OPOST|ONLCR|OXTABS;
455	cflag = CREAD;
456	lflag = ICANON|ISIG|IEXTEN;
457
458	if (ISSET(flags, TANDEM))
459		SET(iflag, IXOFF);
460	else
461		CLR(iflag, IXOFF);
462	if (ISSET(flags, ECHO))
463		SET(lflag, ECHO);
464	else
465		CLR(lflag, ECHO);
466	if (ISSET(flags, CRMOD)) {
467		SET(iflag, ICRNL);
468		SET(oflag, ONLCR);
469	} else {
470		CLR(iflag, ICRNL);
471		CLR(oflag, ONLCR);
472	}
473	if (ISSET(flags, XTABS))
474		SET(oflag, OXTABS);
475	else
476		CLR(oflag, OXTABS);
477
478
479	if (ISSET(flags, RAW)) {
480		iflag &= IXOFF;
481		CLR(lflag, ISIG|ICANON|IEXTEN);
482		CLR(cflag, PARENB);
483	} else {
484		SET(iflag, BRKINT|IXON|IMAXBEL);
485		SET(lflag, ISIG|IEXTEN);
486		if (ISSET(flags, CBREAK))
487			CLR(lflag, ICANON);
488		else
489			SET(lflag, ICANON);
490		switch (ISSET(flags, ANYP)) {
491		case 0:
492			CLR(cflag, PARENB);
493			break;
494		case ANYP:
495			SET(cflag, PARENB);
496			CLR(iflag, INPCK);
497			break;
498		case EVENP:
499			SET(cflag, PARENB);
500			SET(iflag, INPCK);
501			CLR(cflag, PARODD);
502			break;
503		case ODDP:
504			SET(cflag, PARENB);
505			SET(iflag, INPCK);
506			SET(cflag, PARODD);
507			break;
508		}
509	}
510
511	/* Nothing we can do with CRTBS. */
512	if (ISSET(flags, PRTERA))
513		SET(lflag, ECHOPRT);
514	else
515		CLR(lflag, ECHOPRT);
516	if (ISSET(flags, CRTERA))
517		SET(lflag, ECHOE);
518	else
519		CLR(lflag, ECHOE);
520	/* Nothing we can do with TILDE. */
521	if (ISSET(flags, MDMBUF))
522		SET(cflag, MDMBUF);
523	else
524		CLR(cflag, MDMBUF);
525	if (ISSET(flags, NOHANG))
526		CLR(cflag, HUPCL);
527	else
528		SET(cflag, HUPCL);
529	if (ISSET(flags, CRTKIL))
530		SET(lflag, ECHOKE);
531	else
532		CLR(lflag, ECHOKE);
533	if (ISSET(flags, CTLECH))
534		SET(lflag, ECHOCTL);
535	else
536		CLR(lflag, ECHOCTL);
537	if (!ISSET(flags, DECCTQ))
538		SET(iflag, IXANY);
539	else
540		CLR(iflag, IXANY);
541	CLR(lflag, TOSTOP|FLUSHO|PENDIN|NOFLSH);
542	SET(lflag, ISSET(flags, TOSTOP|FLUSHO|PENDIN|NOFLSH));
543
544	if (ISSET(flags, RAW|LITOUT|PASS8)) {
545		CLR(cflag, CSIZE);
546		SET(cflag, CS8);
547		if (!ISSET(flags, RAW|PASS8))
548			SET(iflag, ISTRIP);
549		else
550			CLR(iflag, ISTRIP);
551		if (!ISSET(flags, RAW|LITOUT))
552			SET(oflag, OPOST);
553		else
554			CLR(oflag, OPOST);
555	} else {
556		CLR(cflag, CSIZE);
557		SET(cflag, CS7);
558		SET(iflag, ISTRIP);
559		SET(oflag, OPOST);
560	}
561
562	tmode.c_iflag = iflag;
563	tmode.c_oflag = oflag;
564	tmode.c_cflag = cflag;
565	tmode.c_lflag = lflag;
566}
567#endif
568
569#ifdef XXX_DELAY
570struct delayval {
571	unsigned	delay;		/* delay in ms */
572	int		bits;
573};
574
575/*
576 * below are random guesses, I can't be bothered checking
577 */
578
579struct delayval	crdelay[] = {
580	{ 1,		CR1 },
581	{ 2,		CR2 },
582	{ 3,		CR3 },
583	{ 83,		CR1 },
584	{ 166,		CR2 },
585	{ 0,		CR3 },
586};
587
588struct delayval nldelay[] = {
589	{ 1,		NL1 },		/* special, calculated */
590	{ 2,		NL2 },
591	{ 3,		NL3 },
592	{ 100,		NL2 },
593	{ 0,		NL3 },
594};
595
596struct delayval	bsdelay[] = {
597	{ 1,		BS1 },
598	{ 0,		0 },
599};
600
601struct delayval	ffdelay[] = {
602	{ 1,		FF1 },
603	{ 1750,		FF1 },
604	{ 0,		FF1 },
605};
606
607struct delayval	tbdelay[] = {
608	{ 1,		TAB1 },
609	{ 2,		TAB2 },
610	{ 3,		XTABS },	/* this is expand tabs */
611	{ 100,		TAB1 },
612	{ 0,		TAB2 },
613};
614
615int
616delaybits()
617{
618	register int f;
619
620	f  = adelay(CD, crdelay);
621	f |= adelay(ND, nldelay);
622	f |= adelay(FD, ffdelay);
623	f |= adelay(TD, tbdelay);
624	f |= adelay(BD, bsdelay);
625	return (f);
626}
627
628int
629adelay(ms, dp)
630	register ms;
631	register struct delayval *dp;
632{
633	if (ms == 0)
634		return (0);
635	while (dp->delay && ms > dp->delay)
636		dp++;
637	return (dp->bits);
638}
639#endif
640
641char	editedhost[MAXHOSTNAMELEN];
642
643void
644edithost(pat)
645	register const char *pat;
646{
647	register const char *host = HN;
648	register char *res = editedhost;
649
650	if (!pat)
651		pat = "";
652	while (*pat) {
653		switch (*pat) {
654
655		case '#':
656			if (*host)
657				host++;
658			break;
659
660		case '@':
661			if (*host)
662				*res++ = *host++;
663			break;
664
665		default:
666			*res++ = *pat;
667			break;
668
669		}
670		if (res == &editedhost[sizeof editedhost - 1]) {
671			*res = '\0';
672			return;
673		}
674		pat++;
675	}
676	if (*host)
677		strncpy(res, host, sizeof editedhost - (res - editedhost) - 1);
678	else
679		*res = '\0';
680	editedhost[sizeof editedhost - 1] = '\0';
681}
682
683static struct speedtab {
684	int	speed;
685	int	uxname;
686} speedtab[] = {
687	{ 50,	B50 },
688	{ 75,	B75 },
689	{ 110,	B110 },
690	{ 134,	B134 },
691	{ 150,	B150 },
692	{ 200,	B200 },
693	{ 300,	B300 },
694	{ 600,	B600 },
695	{ 1200,	B1200 },
696	{ 1800,	B1800 },
697	{ 2400,	B2400 },
698	{ 4800,	B4800 },
699	{ 9600,	B9600 },
700	{ 19200, EXTA },
701	{ 19,	EXTA },		/* for people who say 19.2K */
702	{ 38400, EXTB },
703	{ 38,	EXTB },
704	{ 7200,	EXTB },		/* alternative */
705	{ 57600, B57600 },
706	{ 115200, B115200 },
707	{ 0 }
708};
709
710int
711speed(val)
712	int val;
713{
714	register struct speedtab *sp;
715
716	if (val <= B115200)
717		return (val);
718
719	for (sp = speedtab; sp->speed; sp++)
720		if (sp->speed == val)
721			return (sp->uxname);
722
723	return (B300);		/* default in impossible cases */
724}
725
726void
727makeenv(env)
728	char *env[];
729{
730	static char termbuf[128] = "TERM=";
731	register char *p, *q;
732	register char **ep;
733
734	ep = env;
735	if (TT && *TT) {
736		strcat(termbuf, TT);
737		*ep++ = termbuf;
738	}
739	if ((p = EV)) {
740		q = p;
741		while ((q = strchr(q, ','))) {
742			*q++ = '\0';
743			*ep++ = p;
744			p = q;
745		}
746		if (*p)
747			*ep++ = p;
748	}
749	*ep = (char *)0;
750}
751
752/*
753 * This speed select mechanism is written for the Develcon DATASWITCH.
754 * The Develcon sends a string of the form "B{speed}\n" at a predefined
755 * baud rate. This string indicates the user's actual speed.
756 * The routine below returns the terminal type mapped from derived speed.
757 */
758struct	portselect {
759	const char	*ps_baud;
760	const char	*ps_type;
761} portspeeds[] = {
762	{ "B110",	"std.110" },
763	{ "B134",	"std.134" },
764	{ "B150",	"std.150" },
765	{ "B300",	"std.300" },
766	{ "B600",	"std.600" },
767	{ "B1200",	"std.1200" },
768	{ "B2400",	"std.2400" },
769	{ "B4800",	"std.4800" },
770	{ "B9600",	"std.9600" },
771	{ "B19200",	"std.19200" },
772	{ 0 }
773};
774
775const char *
776portselector()
777{
778	char c, baud[20];
779	const char *type = "default";
780	register struct portselect *ps;
781	int len;
782
783	alarm(5*60);
784	for (len = 0; len < sizeof (baud) - 1; len++) {
785		if (read(STDIN_FILENO, &c, 1) <= 0)
786			break;
787		c &= 0177;
788		if (c == '\n' || c == '\r')
789			break;
790		if (c == 'B')
791			len = 0;	/* in case of leading garbage */
792		baud[len] = c;
793	}
794	baud[len] = '\0';
795	for (ps = portspeeds; ps->ps_baud; ps++)
796		if (strcmp(ps->ps_baud, baud) == 0) {
797			type = ps->ps_type;
798			break;
799		}
800	sleep(2);	/* wait for connection to complete */
801	return (type);
802}
803
804/*
805 * This auto-baud speed select mechanism is written for the Micom 600
806 * portselector. Selection is done by looking at how the character '\r'
807 * is garbled at the different speeds.
808 */
809const char *
810autobaud()
811{
812	int rfds;
813	struct timeval timeout;
814	char c;
815	const char *type = "9600-baud";
816
817	(void)tcflush(0, TCIOFLUSH);
818	rfds = 1 << 0;
819	timeout.tv_sec = 5;
820	timeout.tv_usec = 0;
821	if (select(32, (fd_set *)&rfds, (fd_set *)NULL,
822	    (fd_set *)NULL, &timeout) <= 0)
823		return (type);
824	if (read(STDIN_FILENO, &c, sizeof(char)) != sizeof(char))
825		return (type);
826	timeout.tv_sec = 0;
827	timeout.tv_usec = 20;
828	(void) select(32, (fd_set *)NULL, (fd_set *)NULL,
829	    (fd_set *)NULL, &timeout);
830	(void)tcflush(0, TCIOFLUSH);
831	switch (c & 0377) {
832
833	case 0200:		/* 300-baud */
834		type = "300-baud";
835		break;
836
837	case 0346:		/* 1200-baud */
838		type = "1200-baud";
839		break;
840
841	case  015:		/* 2400-baud */
842	case 0215:
843		type = "2400-baud";
844		break;
845
846	default:		/* 4800-baud */
847		type = "4800-baud";
848		break;
849
850	case 0377:		/* 9600-baud */
851		type = "9600-baud";
852		break;
853	}
854	return (type);
855}
856