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 36 static char sccsid[] = "@(#)from: subr.c 8.1 (Berkeley) 6/4/93"; 37 #endif 38 static 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 64 static void compatflags __P((long)); 65 #endif 66 67 /* 68 * Get a table entry. 69 */ 70 void 71 gettable(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 186 void 187 gendefaults() 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 206 void 207 setdefaults() 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 225 static char ** 226 charnames[] = { 227 &ER, &KL, &IN, &QU, &XN, &XF, &ET, &BK, 228 &SU, &DS, &RP, &FL, &WE, &LN, 0 229 }; 230 231 static char * 232 charvars[] = { 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 240 void 241 setchars() 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 260 void 261 setflags(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 436 out: 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 */ 447 void 448 compatflags(flags) 449 register 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 570 struct 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 579 struct delayval crdelay[] = { 580 { 1, CR1 }, 581 { 2, CR2 }, 582 { 3, CR3 }, 583 { 83, CR1 }, 584 { 166, CR2 }, 585 { 0, CR3 }, 586 }; 587 588 struct delayval nldelay[] = { 589 { 1, NL1 }, /* special, calculated */ 590 { 2, NL2 }, 591 { 3, NL3 }, 592 { 100, NL2 }, 593 { 0, NL3 }, 594 }; 595 596 struct delayval bsdelay[] = { 597 { 1, BS1 }, 598 { 0, 0 }, 599 }; 600 601 struct delayval ffdelay[] = { 602 { 1, FF1 }, 603 { 1750, FF1 }, 604 { 0, FF1 }, 605 }; 606 607 struct delayval tbdelay[] = { 608 { 1, TAB1 }, 609 { 2, TAB2 }, 610 { 3, XTABS }, /* this is expand tabs */ 611 { 100, TAB1 }, 612 { 0, TAB2 }, 613 }; 614 615 int 616 delaybits() 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 628 int 629 adelay(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 641 char editedhost[MAXHOSTNAMELEN]; 642 643 void 644 edithost(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 683 static 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 711 int 712 speed(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 727 void 728 makeenv(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 */ 759 struct 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 776 const char * 777 portselector() 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 */ 810 const char * 811 autobaud() 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 } 857