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