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 "$Id: subr.c,v 1.13 1997/11/21 07:43:52 charnier Exp $";
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 { 230400, B230400 },
708 { 0 }
709};
710
711int
712speed(val)
713 int val;
714{
715 register struct speedtab *sp;
716
717 if (val <= B230400)
718 return (val);
719
720 for (sp = speedtab; sp->speed; sp++)
721 if (sp->speed == val)
722 return (sp->uxname);
723
724 return (B300); /* default in impossible cases */
725}
726
727void
728makeenv(env)
729 char *env[];
730{
731 static char termbuf[128] = "TERM=";
732 register char *p, *q;
733 register char **ep;
734
735 ep = env;
736 if (TT && *TT) {
737 strcat(termbuf, TT);
738 *ep++ = termbuf;
739 }
740 if ((p = EV)) {
741 q = p;
742 while ((q = strchr(q, ','))) {
743 *q++ = '\0';
744 *ep++ = p;
745 p = q;
746 }
747 if (*p)
748 *ep++ = p;
749 }
750 *ep = (char *)0;
751}
752
753/*
754 * This speed select mechanism is written for the Develcon DATASWITCH.
755 * The Develcon sends a string of the form "B{speed}\n" at a predefined
756 * baud rate. This string indicates the user's actual speed.
757 * The routine below returns the terminal type mapped from derived speed.
758 */
759struct portselect {
760 const char *ps_baud;
761 const char *ps_type;
762} portspeeds[] = {
763 { "B110", "std.110" },
764 { "B134", "std.134" },
765 { "B150", "std.150" },
766 { "B300", "std.300" },
767 { "B600", "std.600" },
768 { "B1200", "std.1200" },
769 { "B2400", "std.2400" },
770 { "B4800", "std.4800" },
771 { "B9600", "std.9600" },
772 { "B19200", "std.19200" },
773 { 0 }
774};
775
776const char *
777portselector()
778{
779 char c, baud[20];
780 const char *type = "default";
781 register struct portselect *ps;
782 int len;
783
784 alarm(5*60);
785 for (len = 0; len < sizeof (baud) - 1; len++) {
786 if (read(STDIN_FILENO, &c, 1) <= 0)
787 break;
788 c &= 0177;
789 if (c == '\n' || c == '\r')
790 break;
791 if (c == 'B')
792 len = 0; /* in case of leading garbage */
793 baud[len] = c;
794 }
795 baud[len] = '\0';
796 for (ps = portspeeds; ps->ps_baud; ps++)
797 if (strcmp(ps->ps_baud, baud) == 0) {
798 type = ps->ps_type;
799 break;
800 }
801 sleep(2); /* wait for connection to complete */
802 return (type);
803}
804
805/*
806 * This auto-baud speed select mechanism is written for the Micom 600
807 * portselector. Selection is done by looking at how the character '\r'
808 * is garbled at the different speeds.
809 */
810const char *
811autobaud()
812{
813 int rfds;
814 struct timeval timeout;
815 char c;
816 const char *type = "9600-baud";
817
818 (void)tcflush(0, TCIOFLUSH);
819 rfds = 1 << 0;
820 timeout.tv_sec = 5;
821 timeout.tv_usec = 0;
822 if (select(32, (fd_set *)&rfds, (fd_set *)NULL,
823 (fd_set *)NULL, &timeout) <= 0)
824 return (type);
825 if (read(STDIN_FILENO, &c, sizeof(char)) != sizeof(char))
826 return (type);
827 timeout.tv_sec = 0;
828 timeout.tv_usec = 20;
829 (void) select(32, (fd_set *)NULL, (fd_set *)NULL,
830 (fd_set *)NULL, &timeout);
831 (void)tcflush(0, TCIOFLUSH);
832 switch (c & 0377) {
833
834 case 0200: /* 300-baud */
835 type = "300-baud";
836 break;
837
838 case 0346: /* 1200-baud */
839 type = "1200-baud";
840 break;
841
842 case 015: /* 2400-baud */
843 case 0215:
844 type = "2400-baud";
845 break;
846
847 default: /* 4800-baud */
848 type = "4800-baud";
849 break;
850
851 case 0377: /* 9600-baud */
852 type = "9600-baud";
853 break;
854 }
855 return (type);
856}
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 "$Id: subr.c,v 1.13 1997/11/21 07:43:52 charnier Exp $";
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 { 230400, B230400 },
708 { 0 }
709};
710
711int
712speed(val)
713 int val;
714{
715 register struct speedtab *sp;
716
717 if (val <= B230400)
718 return (val);
719
720 for (sp = speedtab; sp->speed; sp++)
721 if (sp->speed == val)
722 return (sp->uxname);
723
724 return (B300); /* default in impossible cases */
725}
726
727void
728makeenv(env)
729 char *env[];
730{
731 static char termbuf[128] = "TERM=";
732 register char *p, *q;
733 register char **ep;
734
735 ep = env;
736 if (TT && *TT) {
737 strcat(termbuf, TT);
738 *ep++ = termbuf;
739 }
740 if ((p = EV)) {
741 q = p;
742 while ((q = strchr(q, ','))) {
743 *q++ = '\0';
744 *ep++ = p;
745 p = q;
746 }
747 if (*p)
748 *ep++ = p;
749 }
750 *ep = (char *)0;
751}
752
753/*
754 * This speed select mechanism is written for the Develcon DATASWITCH.
755 * The Develcon sends a string of the form "B{speed}\n" at a predefined
756 * baud rate. This string indicates the user's actual speed.
757 * The routine below returns the terminal type mapped from derived speed.
758 */
759struct portselect {
760 const char *ps_baud;
761 const char *ps_type;
762} portspeeds[] = {
763 { "B110", "std.110" },
764 { "B134", "std.134" },
765 { "B150", "std.150" },
766 { "B300", "std.300" },
767 { "B600", "std.600" },
768 { "B1200", "std.1200" },
769 { "B2400", "std.2400" },
770 { "B4800", "std.4800" },
771 { "B9600", "std.9600" },
772 { "B19200", "std.19200" },
773 { 0 }
774};
775
776const char *
777portselector()
778{
779 char c, baud[20];
780 const char *type = "default";
781 register struct portselect *ps;
782 int len;
783
784 alarm(5*60);
785 for (len = 0; len < sizeof (baud) - 1; len++) {
786 if (read(STDIN_FILENO, &c, 1) <= 0)
787 break;
788 c &= 0177;
789 if (c == '\n' || c == '\r')
790 break;
791 if (c == 'B')
792 len = 0; /* in case of leading garbage */
793 baud[len] = c;
794 }
795 baud[len] = '\0';
796 for (ps = portspeeds; ps->ps_baud; ps++)
797 if (strcmp(ps->ps_baud, baud) == 0) {
798 type = ps->ps_type;
799 break;
800 }
801 sleep(2); /* wait for connection to complete */
802 return (type);
803}
804
805/*
806 * This auto-baud speed select mechanism is written for the Micom 600
807 * portselector. Selection is done by looking at how the character '\r'
808 * is garbled at the different speeds.
809 */
810const char *
811autobaud()
812{
813 int rfds;
814 struct timeval timeout;
815 char c;
816 const char *type = "9600-baud";
817
818 (void)tcflush(0, TCIOFLUSH);
819 rfds = 1 << 0;
820 timeout.tv_sec = 5;
821 timeout.tv_usec = 0;
822 if (select(32, (fd_set *)&rfds, (fd_set *)NULL,
823 (fd_set *)NULL, &timeout) <= 0)
824 return (type);
825 if (read(STDIN_FILENO, &c, sizeof(char)) != sizeof(char))
826 return (type);
827 timeout.tv_sec = 0;
828 timeout.tv_usec = 20;
829 (void) select(32, (fd_set *)NULL, (fd_set *)NULL,
830 (fd_set *)NULL, &timeout);
831 (void)tcflush(0, TCIOFLUSH);
832 switch (c & 0377) {
833
834 case 0200: /* 300-baud */
835 type = "300-baud";
836 break;
837
838 case 0346: /* 1200-baud */
839 type = "1200-baud";
840 break;
841
842 case 015: /* 2400-baud */
843 case 0215:
844 type = "2400-baud";
845 break;
846
847 default: /* 4800-baud */
848 type = "4800-baud";
849 break;
850
851 case 0377: /* 9600-baud */
852 type = "9600-baud";
853 break;
854 }
855 return (type);
856}